2012-04-26 53 views
16

假设我有这个模型ASP网页API补丁实现

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

我送这是JSON数据到我的控制器作为补丁请求。 这只是一个复选框的动作。 我认为这让SENCE,我只是想发送的到我的服务器,而不是整个模型。

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

什么我的WebAPI控制器需要的样子,以便正确地处理此,简单,JSON补丁的要求吗?我应该使用web api吗?还是应该使用mvc更多的rpc风格的方法?

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

谢谢你的时间。

+0

您可以使用支持ASP.NET,ASP.NET Core和PCL for Xamarin的JsonPatch。 https://github.com/KevinDockx/JsonPatch。好文章可以在这里找到http://benfoster.io/blog/aspnet-core-json-patch-partial-api-updates – 2016-11-10 05:13:54

+0

这是一个不同的问题,我认为。我的模型不是基于json的。实际的状态更新将如何发生应该由实施者决定。我不想将某些RFC规范翻译成SQL查询或实体突变。 – 2016-11-10 05:18:52

回答

11

你可以找到的OData预发布的NuGet包补丁特性:Microsoft.AspNet.WebApi.OData

信息,你可以用它来创建用于处理PATCH动作可在部分更新(PATCH请求)的博客文章OData support in ASP.NET Web API部分找到。

+1

查看此示例以通过json.net序列化程序进行修补而不依赖于oData数据格式 - https: //aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/DeltaJsonDeserialization/ – 2015-02-11 23:32:36

1

的ASP.NET Web API似乎缺少UpdateModelTryUpdateModel

在ASP.NET MVC,你可以用它们来达到预期的效果。我在ASP.NET Web Stack中创建了一个work item,您可以投票,如果得到足够的投票,它将被实现。

12

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

其次,你问的Web API为你这样做有对象序列化恰恰是将部分更新的对象没有这样的概念。会有这么多的约定达成一致,空值是什么意思,空值是什么,我怎么说“不更新这个DateTime”。关于相关对象,子项目呢?你如何导致儿童项目被删除?除非CLR团队实现了只包含另一类型成员子集的某种类型的概念,否则部分更新和对象序列化不会很好地结合在一起。

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

至于我自己,我创造了我使用这样做就像一个形式,但在它能够处理hierarchial数据更先进,它保持着一个以更新部分更新新的媒体类型。

+0

+1。您的媒体类型格式化程序可以包含在web api contrib中吗?这是一种常见的情况,我可以想象这种功能经常被要求。 – Aliostad 2012-04-26 12:56:56

+0

谢谢你的回答,如果我只想更新我的模型的一个字段(这种情况下的'完成'复选框字段),那么正确的方法是什么? 我应该放弃web api吗?我怎样才能做到这一点而不会失去我的模型验证?很难相信这样一个简单的行动将不可能与“最新的最新”在asp.net技术 – 2012-04-26 12:59:08

+0

我编辑了我的问题,以更好地描述问题。 – 2012-04-26 13:09:42

0

我用Microsoft.AspNet.WebApi.OData为我的项目,我有一些问题JSON的(带有号码在我的情况下工作)。另外,OData包有一些依赖关系,从我的角度来看,对于单个功能来说太大了(大约7MB的所有依赖关系)。

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

如何使用

使用安装软件包:

Install-Package SimplePatch 

然后在你的控制器:

[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方法之后仅添加两行代码:

entity.Patch(entityToPatch); 

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

此外,还可以排除某些属性,当Patch方法被调用来进行更新。 的Global.asax或Startup.cs

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

这是有用的,当你与实体工作,你不希望创建一个模型。