在尝试使用 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
orInStock
属性,所以反序列化了Price=0
and 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 我真的不认为它们是前进的方向。它们增加了复杂性并降低了可维护性,同时不会给你任何东西,比如字典或集合。