C# 不可为空类型上的MVC4WebAPI验证
在尝试使用WebAPI创建RESTful web服务时,有一件事一直困扰着我:如何处理不可为null的类型 示例对象: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
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数据。