在尝试使用WebAPI创建RESTful Web服务时,有一件事一直困扰着我:如何处理非可空类型?
示例对象:
public class Product {
public Guid Id {get; set;}
public string Name {get; set;}
public decimal Price {get; set;}
public bool InStock {get; set;}
}
示例控制器方法:
public void Put (Product product){
productRepository.Update(product);
}
示例json调用PUT:
{
"Id": "8E28961C-C99E-4EED-9F33-44D33C107A33",
"Name": "Generic Bottled Water"
}
所以我们现在处于困境中,json调用不包括请求中的Price
或InStock
属性,因此反序列化Price=0
和Instock=false
。在这个阶段,现在无法验证请求,因为我们无法知道他们是故意设置这些值,还是因为它们不存在而被默认。
让他们无所事事!我听到有人在听到呐喊声。是的,我可以通过在每个声明的末尾添加少量?
来使我的所有值类型都可以为空。这对我来说虽然是一个可怕的想法和滥用可空类型。模型视图控件是独立的,如果您的模型必须关心控制器将如何使用它,那么您已经使您的关注点无效。
强迫他们通过所有物业!我听到别人哭了。然而,这会导致带宽的浪费,因为多余的数据飞回来并且排在第四位。
那么答案是什么呢?我的问题是2美分,如果你不想为了控制器而牺牲你的核心模型,你也不想强迫你的api消费者每次都发送完整的对象然后你只留下一个溶液
将传递的所有内容序列化到集合中,然后验证集合以确定是否存在所有必需的属性。所以你最终可能得到以下结论:
public void Put (Guid productId, Dictionary<string, object> productDictionary){
...retrieve and validate existing product.
if (productDictionary.ContainsKey("Price"))
existingProduct.Price = productDictionary["Price"];
if (productDictionary.ContainsKey("InStock"))
existingProduct.Price = productDictionary["InStock"];
productRepository.Update(existingProduct);
}
如果我诚实,我也不会这样说,但我没有看到真正的选择。我真的不想让我的所有对象属性都可以为空,也不想强制客户端传递所有数据。
有没有人对如何解决这个问题有更好的建议?也许是我遗漏的一些验证条款或库?一些可以解决这个问题的架构模式?
我真的觉得序列化到对象模型有点虚假经济。
修改
我重新打开了这个问题,因为研究DTO我真的不认为他们是前进的方向。它们会增加复杂性并降低可维护性,同时又不会给你任何字典或集合。
答案 0 :(得分:3)
这是您应该专门为控制器操作创建单独的视图模型的时间。视图模型可以具有可空属性,然后您可以在控制器中创建的Product实例上设置所需的任何内容。
答案 1 :(得分:0)
自定义模型装订器会解决您的问题吗?您可以决定如何实例化模型以及要填充的属性以及基于请求传递给您的信息的方式。这基本上与您提供的解决方案完全相同,但没有序列化和所有额外处理,就像您自己创建模型一样。