我正在使用HttpPatch来部分更新对象。为了实现这一点,我正在使用OData的Delta和Patch方法(这里提到:What's the currently recommended way of performing partial updates with Web API?)。一切似乎工作正常,但注意到映射器区分大小写;当传递以下对象时,属性将获得更新的值:
{
"Title" : "New title goes here",
"ShortDescription" : "New text goes here"
}
但是当我传递具有较低或驼峰式属性的相同对象时,Patch不起作用 - 新值不会通过,因此看起来反序列化和属性映射存在问题,即:“shortDescription”到“ShortDescription”。
是否有使用Patch忽略区分大小写的配置部分?
供参考:
在输出中,我使用以下格式化程序具有驼峰式属性(遵循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
}
答案 0 :(得分:7)
简短回答,没有没有配置选项可以撤消区分大小写(据我所知)
答案很长:我今天和你有同样的问题,这就是我解决这个问题的方法。
我发现它必须区分大小写令人难以置信,因此我决定取消整个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);
}
}
}
然后我让我的所有模型类继承自* 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。
答案 1 :(得分:3)
使用自定义合约解析程序可以很容易地完成它,该解析程序继承CamelCasePropertyNamesContractResolver并实现CreateContract方法,该方法查看delta的具体类型并获取实际的属性名称,而不是使用来自json的属性名称。摘要如下:
public class DeltaContractResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
// This class special cases the JsonContract for just the Delta<T> 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;
}
}