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似乎缺少UpdateModel
, TryUpdateModel
等。
在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); });
当您使用实体并且不想创建模型时,这非常有用。