asp web api补丁实现

时间:2012-04-26 11:50:36

标签: c# asp.net rest model asp.net-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方法?

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

感谢您的时间。

4 个答案:

答案 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似乎缺少UpdateModelTryUpdateModel

在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();

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