asp.net mvc web api使用OData Patch进行部分更新

我正在使用HttpPatch来部分更新对象。 为了实现这一点,我使用OData的Delta和Patch方法(这里提到: 目前推荐的使用Web API执行部分更新的方法是什么? )。 一切似乎工作正常,但注意到映射器区分大小写; 当传递以下对象时,属性将获得更新的值:

{ "Title" : "New title goes here", "ShortDescription" : "New text goes here" } 

但是当我传递具有较低或驼峰式属性的相同对象时,Patch不起作用 – 新值不会通过,因此看起来反序列化和属性映射存在问题,即:“shortDescription”到“ShortDescription” ”。

是否有使用Patch忽略区分大小写的配置部分?

供参考:

在输出中,我使用以下格式化程序的camel-case属性(遵循REST最佳实践):

 //formatting JsonSerializerSettings jss = new JsonSerializerSettings(); jss.ContractResolver = new CamelCasePropertyNamesContractResolver(); config.Formatters.JsonFormatter.SerializerSettings = jss; //sample output { "title" : "First", "shortDescription" : "First post!" } 

然而,我的模型类遵循C#/ .NET格式约定:

 public class Entry { public string Title { get; set;} public string ShortDescription { get; set;} //rest of the code omitted } 

简短的回答,没有没有配置选项来撤消区分大小写(据我所知)

答案很长:我今天和你有同样的问题,这就是我如何解决它的问题。
我发现它必须区分大小写非常令人讨厌,因此我决定取消整个oData部分,因为它是一个巨大的库我们正在滥用….

可以在我的github github上找到此实现的一个示例

我决定实施自己的补丁方法,因为那是我们实际缺乏的肌肉。 我创建了以下抽象类:

 public abstract class MyModel { public void Patch(Object u) { var props = from p in this.GetType().GetProperties() let attr = p.GetCustomAttribute(typeof(NotPatchableAttribute)) where attr == null select p; foreach (var prop in props) { var val = prop.GetValue(this, null); if (val != null) prop.SetValue(u, val); } } } 

然后我让我的所有模型类inheritance自* MyModel *。 注意我使用* let *的行,我将在以后解释。 因此,现在您可以从控制器操作中删除Delta,并再次使其成为Entry,就像使用put方法一样。 例如

 public IHttpActionResult PatchUser(int id, Entry newEntry) 

您仍然可以按照以下方式使用补丁方法:

 var entry = dbContext.Entries.SingleOrDefault(p => p.ID == id); newEntry.Patch(entry); dbContext.SaveChanges(); 

现在,让我们回到原点

 let attr = p.GetCustomAttribute(typeof(NotPatchableAttribute)) 

我发现存在安全风险,任何属性都可以使用补丁请求进行更新。 例如,您现在可能希望修补程序可以更改ID。 我创建了一个自定义属性来装饰我的属性。 NotPatchable属性:

 public class NotPatchableAttribute : Attribute {} 

您可以像使用任何其他属性一样使用它:

 public class User : MyModel { [NotPatchable] public int ID { get; set; } [NotPatchable] public bool Deleted { get; set; } public string FirstName { get; set; } } 

在此调用中,通过补丁方法无法更改Deleted和ID属性。

我希望这也能为你解决。 如果您有任何疑问,请随时发表评论。

我添加了一个截图,检查了一个新的mvc 5项目中的道具。 如您所见,结果视图中填充了Title和ShortDescription。

检查道具的示例

使用自定义合约解析器可以非常轻松地完成它,该解析器inheritanceCamelCasePropertyNamesContractResolver并实现CreateContract方法,该方法查看delta的具体类型并获取实际属性名称,而不是使用来自json的属性名称。 摘要如下:

 public class DeltaContractResolver : CamelCasePropertyNamesContractResolver { protected override JsonContract CreateContract(Type objectType) { // This class special cases the JsonContract for just the Delta class. All other types should function // as usual. if (objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Delta<>) && objectType.GetGenericArguments().Length == 1) { var contract = CreateDynamicContract(objectType); contract.Properties.Clear(); var underlyingContract = CreateObjectContract(objectType.GetGenericArguments()[0]); var underlyingProperties = underlyingContract.CreatedType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var property in underlyingContract.Properties) { property.DeclaringType = objectType; property.ValueProvider = new DynamicObjectValueProvider() { PropertyName = this.ResolveName(underlyingProperties, property.PropertyName), }; contract.Properties.Add(property); } return contract; } return base.CreateContract(objectType); } private string ResolveName(PropertyInfo[] properties, string propertyName) { var prop = properties.SingleOrDefault(p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase)); if (prop != null) { return prop.Name; } return propertyName; } }