asp web api补丁实现

假设我有这个模型

public partial class Todo { public int id { get; set; } public string content { get; set; } public bool done { get; set; } } 

我将此作为json数据发送到我的控制器作为补丁请求。 这绝对是一个复选框的动作。 我认为我只想把它发送到我的服务器,而不是整个模型。

 { "id":1, "done" : true } 

为了正确处理这个简单的json补丁请求,我的WebApi控制器需要看起来是什么样的? 我应该使用web api,还是应该使用更多rpc风格的mvc方法?

这似乎是一件非常基本的事情,但我似乎无法做到正确! 我想我可能需要在我的控制器方法中使用不同的参数,但我不确定。

感谢您的时间。

您可以在OData预发布Nuget包中找到PATCHfunction: Microsoft.AspNet.WebApi.OData 。

有关如何使用它来创建处理PATCH的操作的信息可以在博客文章的部分更新(PATCH请求)部分中找到,该部分关于ASP.NET Web API中的OData支持 。

将方法更改为PATCH不会以任何方式更改Web API行为。 没有用于进行部分更新的内置机制。 长期没有PATCH方法的原因之一是没有普遍存在的媒体类型来将补丁应用于资源。

其次,您要求Web API为您执行对象序列化,因此没有应用部分更新对象的概念。 会有很多约定要达成一致,null值是什么意思,空值怎么样,我怎么说“不要更新这个DateTime”。 相关物品,儿童用品怎么样? 如何删除子项目? 除非CLR团队实现某种类型的概念,该概念仅包含来自其他类型的成员的子集,否则部分更新和对象序列化将无法很好地结合在一起。

Aliostad提到UpdateModel,这可以在从HTML表单更新时实现,因为媒体类型application/x-www-form-urlencoded明确允许任意一组名称值对。 没有“对象序列化”正在进行。 它只是匹配表单中的名称与Model对象上的名称的匹配。

对于我自己,我创建了一种新的媒体类型,用于进行部分更新,其工作方式类似于表单,但更先进,因为它可以处理分层数据,并维护更新的顺序。

ASP.NET Web API似乎缺少UpdateModelTryUpdateModel等。

在ASP.NET MVC中,您可以使用它们来实现所需的效果。 我在ASP.NET Web Stack中创建了一个工作项 ,您可以投票,如果获得足够的投票,它将被实现。

我为我的项目使用了Microsoft.AspNet.WebApi.OData ,并且在使用JSON时遇到了一些问题(在我的情况下使用数字)。 此外,OData包有一些依赖关系,从我的角度来看,对于单个function来说太大了(所有依赖约7MB)。

所以我开发了一个简单的库, 可以满足您的要求: SimplePatch 。

如何使用

使用以下命令安装包:

 Install-Package SimplePatch 

然后在你的控制器中:

 [HttpPatch] public IHttpActionResult PatchOne(Delta todo) { if (todo.TryGetPropertyValue(nameof(Todo.id), out int id)) { // Entity to update (from your datasource) var todoToPatch = Todos.FirstOrDefault(x => x.id == id); if (todoToPatch == null) return BadRequest("Todo not found"); todo.Patch(todoToPatch); // Now todoToPatch is updated with new values } else { return BadRequest(); } return Ok(); } 

该库也支持大量补丁:

 [HttpPatch] public IHttpActionResult PatchMultiple(DeltaCollection todos) { foreach (var todo in todos) { if (todo.TryGetPropertyValue(nameof(Todo.id), out int id)) { // Entity to update (from your datasource) var entityToPatch = Todos.FirstOrDefault(x => x.id == Convert.ToInt32(id)); if (entityToPatch == null) return BadRequest("Todo not found (Id = " + id + ")"); person.Patch(entityToPatch); } else { return BadRequest("Id property not found for a todo"); } } return Ok(); } 

如果使用Entity Framework,则必须在调用Patch方法后仅添加两行代码:

 entity.Patch(entityToPatch); dbContext.Entry(entityToPatch).State = EntityState.Modified; dbContext.SaveChanges(); 

此外,您可以在调用Patch方法时排除某些要更新的属性。 Global.asax或Startup.cs

 DeltaConfig.Init((cfg) => { cfg.ExcludeProperties(x => x.id); }); 

当您使用实体并且不想创建模型时,这非常有用。