【问题标题】:MVC 4 WebAPI validation on non-nullable types不可为空类型的 MVC 4 WebAPI 验证
【发布时间】:2012-08-24 12:36:04
【问题描述】:

在尝试使用 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 调用不包括请求中的PriceInStock 属性,因此反序列化了Price=0Instock=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 我真的不认为它们是前进的方向。它们增加了复杂性并降低了可维护性,同时除了字典或集合之外没有给您任何东西。

【问题讨论】:

    标签: c# .net asp.net-mvc rest asp.net-web-api


    【解决方案1】:

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

    【讨论】:

    • 我可以看到它背后的逻辑,机器人这不会给你留下一个冗长的代码库吗?如果您有 100 个模型对象,那么您需要 100 个视图模型对象,并且任何更改都需要复制。
    • +1 我们遵循这种方法。我们有简单的 DTO 模型,它们是序列化的类。这是一个很小的开销,可以通过实现映射器来限制 - 可能使用 Automapper github.com/AutoMapper/AutoMapper。在复杂系统上,您不太可能完全将域模型直接映射到您的 REST 资源(例如,将 HATEOAS 元素添加到您的响应对象、扁平化和简化序列化对象等)。
    • David:我们在工作中使用这种方法更多是出于安全原因。如果我们有一个具有 10 个属性的模型,但我们只需要设置其中几个属性的控制器操作,我们会设置一个仅包含这些属性的视图模型。它可以防止更改我们不想更改的值。
    • @rossisdead 这确实有道理,所以我会更深入地研究。我通常只是预先获取正在更新的对象,然后只设置允许避免客户端尝试发送任何 bum 数据的属性。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2012-08-23
      • 1970-01-01
      • 2013-08-07
      • 2013-07-02
      • 2020-10-28
      • 1970-01-01
      • 1970-01-01
      • 2013-08-27
      • 1970-01-01
      相关资源
      最近更新 更多