2

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

4

2 回答 2

3

这是您应该专门为控制器操作创建单独的视图模型的时候。视图模型可以具有可为空的属性,然后您可以在控制器中创建的 Product 实例上设置所需的任何内容。

于 2012-08-24T13:03:02.683 回答
0

自定义模型绑定器会解决您的问题吗?您可以根据请求传递给您的信息来决定如何实例化模型以及要填充哪些属性以及如何填充。这基本上与您提供的解决方案相同,但没有序列化和所有额外的处理,就像您自己创建模型一样。

于 2012-08-24T12:44:06.987 回答