假设我有这个模型
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方法?
这似乎是一件非常基本的事情,但我似乎无法做对! 我想我可能需要在我的控制器方法中使用不同的参数,但我不确定。
感谢您的时间。
答案 0 :(得分:12)
将方法更改为PATCH不会以任何方式更改Web API行为。没有用于进行部分更新的内置机制。长期没有PATCH方法的原因之一是没有普遍存在的媒体类型来将补丁应用于资源。
其次,您要求Web API为您执行对象序列化,因此没有应用部分更新对象的概念。会有很多约定要达成一致,null值是什么意思,空值怎么样,我怎么说“不要更新这个DateTime”。相关对象,子项目怎么样?如何删除子项目?除非CLR团队实现某种类型的概念,该概念只包含来自另一种类型的成员的子集,否则部分更新和对象序列化将无法很好地结合在一起。
Aliostad提到UpdateModel,从HTML表单更新时可以这样做,因为媒体类型application/x-www-form-urlencoded
明确允许任意一组名称值对。没有“对象序列化”正在进行。它只是匹配表单中名称与Model对象上名称的匹配。
对于我自己,我创建了一种新的媒体类型,用于进行部分更新,其工作方式与表单类似,但更先进,因为它可以处理分层数据,并维护更新的顺序。
答案 1 :(得分:12)
您可以在OData预发布Nuget包中找到PATCH功能:Microsoft.AspNet.WebApi.OData。
有关如何使用它来创建处理PATCH的操作的信息,请参阅博客文章中关于OData support in ASP.NET Web API的部分更新(PATCH请求)部分。
答案 2 :(得分:2)
ASP.NET Web API似乎缺少UpdateModel
,TryUpdateModel
等
在ASP.NET MVC中,您可以使用它们来实现所需的效果。我在ASP.NET Web Stack中创建了一个work item,您可以投票,如果获得足够的投票,它将被实现。
答案 3 :(得分:1)
我使用Microsoft.AspNet.WebApi.OData作为我的项目,我在使用JSON时遇到了一些问题(在我的情况下使用数字)。此外,OData包具有一些依赖性,从我的角度来看,对于单个特征来说太大了(所有依赖性约为7MB)。
所以我开发了一个简单的库,可以满足您的要求:SimplePatch。
如何使用
使用以下方法安装软件包:
chatrooms
然后在你的控制器中:
Broadcast::channel('private-chat-room-{chatRoom}', function ($user, $chatRoom) {
$chatRoom = App\Models\ChatRoom::find($chatRoom);
if(in_array(auth()->user()->id, explode(',', $chatRoom->user_ids))) {
return true;
} else {
return false;
}
});
图书馆也支持大量补丁:
Install-Package SimplePatch
如果使用Entity Framework,则在调用[HttpPatch]
public IHttpActionResult PatchOne(Delta<Todo> 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<Todo> 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();
}
此外,您可以在调用Patch
方法时排除某些要更新的属性。
Global.asax或Startup.cs
entity.Patch(entityToPatch);
dbContext.Entry(entityToPatch).State = EntityState.Modified;
dbContext.SaveChanges();
当您使用实体并且不想创建模型时,这非常有用。