Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# asp.net mvc web api使用OData修补程序进行部分更新_C#_Api_Asp.net Mvc 4_Odata - Fatal编程技术网

C# asp.net mvc web api使用OData修补程序进行部分更新

C# asp.net mvc web api使用OData修补程序进行部分更新,c#,api,asp.net-mvc-4,odata,C#,Api,Asp.net Mvc 4,Odata,我正在使用HttpPatch部分更新对象。为了实现这一点,我使用了OData的Delta和Patch方法(这里提到:)。一切似乎都很好,但注意到mapper是区分大小写的;传递以下对象时,属性将获得更新的值: { "Title" : "New title goes here", "ShortDescription" : "New text goes here" } 但当我传递具有小写或驼峰大小写属性的同一对象时,补丁不起作用-新值不会通过,因此反序列化和属性映射似乎存在问题,即:“sh

我正在使用HttpPatch部分更新对象。为了实现这一点,我使用了OData的Delta和Patch方法(这里提到:)。一切似乎都很好,但注意到mapper是区分大小写的;传递以下对象时,属性将获得更新的值:

{
  "Title" : "New title goes here",
  "ShortDescription" : "New text goes here"
}
但当我传递具有小写或驼峰大小写属性的同一对象时,补丁不起作用-新值不会通过,因此反序列化和属性映射似乎存在问题,即:“shortDescription”到“shortDescription”

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

供参考:

在输出时,我使用以下格式化程序具有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上找到

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

然后我让我的所有模型类继承自*MyModel*。注意我使用*let*的那一行,我稍后会解释。现在,您可以从控制器操作中删除Delta,只需将其重新设置为条目,就像put方法一样。例如

您仍然可以按照以前的方式使用修补方法:

var entry = dbContext.Entries.SingleOrDefault(p => p.ID == id);
newEntry.Patch(entry);
dbContext.SaveChanges();
现在,让我们回到台词上来

let attr = p.GetCustomAttribute(typeof(NotPatchableAttribute))
我发现这是一个安全风险,任何属性都可以通过补丁请求进行更新。例如,您现在可能希望修补程序可以更改an ID。我创建了一个自定义属性来装饰我的属性。不可修补属性:

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; }
}
您可以像使用任何其他属性一样使用它:

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; }
}
在此调用中,无法通过patch方法更改Deleted和ID属性

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

我添加了一张我在一个新的MVC5项目中检查道具的截图。如您所见,结果视图中填充了标题和简短描述。


使用继承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;
        }
}
公共类DeltaContractResolver:CamelCasePropertyNamesContractResolver
{
受保护的重写JsonContract CreateContract(类型objectType)
{
//这个类是JsonContract的特例,只用于Delta类。所有其他类型都应该起作用
//像往常一样。
if(objectType.IsGenericType)&&
objectType.GetGenericTypeDefinition()==typeof(增量)&&
objectType.GetGenericArguments().Length==1)
{
var合同=CreateDynamicContract(objectType);
contract.Properties.Clear();
var underyingContract=CreateObjectContract(objectType.GetGenericArguments()[0]);
var基础属性=
underlineContract.CreatedType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach(underyingContract.Properties中的var属性)
{
property.DeclaringType=对象类型;
property.ValueProvider=新的DynamicObjectValueProvider()
{
PropertyName=this.ResolveName(underlyingProperties,property.PropertyName),
};
合同.属性.添加(属性);
}
退货合同;
}
返回base.CreateContract(objectType);
}
私有字符串ResolveName(PropertyInfo[]属性,字符串propertyName)
{
var prop=properties.SingleOrDefault(p=>p.Name.Equals(propertyName,StringComparison.OrdinalIgnoreCase));
如果(prop!=null)
{
返回道具名称;
}
返回propertyName;
}
}

Hi Rik,谢谢你的回答,我已经添加了代码,但是有一些不同之处(现在使用MVC 5),并且它不起作用:`var props=from p in this.GetType().GetProperties()让attr=p.GetCustomAttributes(typeof(NotPatchableAttribute),false)其中attr==null选择p;`但是,该查询不返回任何内容。@303哦。。我正在使用WebAPI2,让我在MVC5上快速测试它,我会给你回复的。。没有什么是无法解决的:)@303我刚刚在一个新的mvc项目中测试了它,它似乎可以工作。为了提高速度,我刚刚调整了编辑方法以使用补丁,它可以正常工作。我将把代码放在github上供您比较。仅供参考:我使用的是.Net 4.5,但出现以下错误:“System.Reflection.PropertyInfo”不包含“GetCustomAttribute”的定义,并且找不到接受“System.Reflection.PropertyInfo”类型第一个参数的扩展方法“GetCustomAttribute”(您缺少using指令或程序集引用吗?)我需要额外的引用吗?@303您需要使用System.Reflection;当然。我刚刚再次克隆了示例应用程序,为其创建了新的解决方案并重新安装(卸载并重新安装)下面的金块包装:实体框架,asp.NETMVC和asp.NETWeb优化框架。在这之后,我所有的参考资料都是好的,我是好的