C# 不可为空类型上的MVC4WebAPI验证

C# 不可为空类型上的MVC4WebAPI验证,c#,.net,asp.net-mvc,rest,asp.net-web-api,C#,.net,Asp.net Mvc,Rest,Asp.net Web Api,在尝试使用WebAPI创建RESTful web服务时,有一件事一直困扰着我:如何处理不可为null的类型 示例对象: 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

在尝试使用WebAPI创建RESTful web服务时,有一件事一直困扰着我:如何处理不可为null的类型

示例对象:

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
。在这个阶段,现在不可能验证请求,因为我们无法知道它们是否有意设置了这些值,或者它们是否因为不存在而被默认

使它们可以为空!我听到有人在勇敢地哭泣。是的,我确实可以通过在每个声明的末尾添加一点
使我的所有值类型都可以为空。但对我来说,这是一个糟糕的想法,是对可空类型的滥用。模型-视图-控件是分开的,这是有原因的,如果您的模型必须关心控制器将如何使用它,那么您已经使您的关注点分离无效

强制他们通过所有属性!我听到别人哭了。然而,这会导致带宽浪费,因为多余的数据会来回传输

那么答案是什么呢。?我对这件事的看法是,如果你不想为了控制器而损害你的核心模型,也不想强迫你的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);
}
public void Put(Guid productId,Dictionary productDictionary){
…检索和验证现有产品。
if(productDictionary.ContainsKey(“价格”))
existingProduct.Price=productDictionary[“Price”];
if(productDictionary.ContainsKey(“InStock”))
existingProduct.Price=productDictionary[“InStock”];
productRepository.Update(现有产品);
}
老实说,我也不特别喜欢这种方式,但我看不到真正的替代方法。我真的不想让我的所有对象属性都为空,也不想强迫客户机传递所有数据

关于如何回避这个问题,有谁有更好的建议吗?可能是我缺少的验证子句或库?一些可以处理这个问题的架构模式

我真的觉得序列化到对象模型有点不经济

编辑


我重新提出这个问题是因为研究DTO我真的不认为它们是前进的方向。它们增加了复杂性,降低了可维护性,同时又不给您任何额外的东西,比如字典或集合。

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

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

我可以看到其背后的逻辑,这不是给您留下了一个详细的代码库吗?如果您有100个模型对象,那么您需要100个视图模型对象,然后需要复制任何更改。+1我们遵循这种方法。我们有简单的DTO模型,它们是序列化的类。这是一个小的开销,可以通过实现映射器(可能使用Automapper)来限制。在复杂系统上,您不可能完全将域模型直接映射到您的REST资源(例如,将HATEOAS元素添加到响应对象中,扁平化和简化序列化对象等)。David:我们在工作中使用这种方法更多是出于安全原因,而不是其他原因。如果我们有一个具有10个属性的模型,但控制器操作只需要设置其中的几个属性,那么我们将设置一个仅包含这些属性的视图模型。它可以防止我们不希望更改的值被更改。@rossisdead它确实有意义,因此我将深入研究。我通常只是预先获取要更新的对象,然后只设置允许的属性,以避免客户端尝试发送任何bum数据。