【发布时间】:2014-02-20 03:34:30
【问题描述】:
根据 web api 团队创建的 OData 示例,我的控制器具有以下支持补丁:
public HttpResponseMessage Patch([FromODataUri] int key, Delta<Foo> item)
{
var dbVersion = myDb.GetById(key);
if(dbVersion == null)
throw Request.EntityNotFound();
item.Patch(dbVersion);
myDb.Update(dbVersion);
return Request.CreateResponse(HttpStatusCode.NoContent);
}
并使用自动生成的客户端(源自DataServiceContext),我提交了一个补丁请求,如下所示:
var foo = svcContainer.Foos.Where (f => f.Id == 1).SingleOrDefault();
foo.Description = "Updated Description";
svcContainer.UpdateObject(foo);
svcContainer.SaveChanges(SaveChangesOptions.PatchOnUpdate);
但是,在 fiddler 中跟踪调用,我看到 Foo 的所有其他属性都被序列化并发送到服务。这是正确的行为吗?我只希望通过网络发送 ID 和描述。另外,如果我调试服务方法并调用
GetChangedPropertyNames 在 item 上,返回其所有属性名称。
我应该在客户端上创建某种 Delta 实例吗?
我了解服务的断开连接性质,因此服务端没有用于跟踪更改的上下文,但是在我看来,api 团队添加了对补丁的支持是有原因的,所以我'想知道客户端是否应该以不同的方式调用更新。
更新
一丁提供的链接解释了如何从客户端创建一个真正的PATCH请求(使用Microsoft.OData.Client 6.2.0及以上创建的Microsoft.OData.Client.DataServiceContext。
为方便起见,这里是代码sn-p:
var svcContainer = new Default.Container(<svcUri>);
var changeTracker = new DataServiceCollection<Foo>(svcContainer.Foos.Where(f => f.Id == 1));
changeTracker[0].Description = "Patched Description";
svcContainer.SaveChanges();
DataServiceCollection 实现属性跟踪,并且使用这种模式,只有更新的属性会发送到服务。
不使用DataServiceCollection,只使用
svcContainer.UpdateObject(foo);
svcContainer.SaveChanges();
尽管有相反的文档,但所有属性仍通过网络发送,至少截至Microsoft.OData.Client 6.7.0
【问题讨论】:
-
使用 PATCH amd delta 时,我们只发布我们想要在 JSON 有效负载中更改的属性。看起来您在示例代码中提交了一个完整的 foo 对象?
-
@eoghank 我已经尝试了几种创建对象的空实例并仅设置 Id 和 selected 属性的变体,但是(使用自动生成的 DataServiceContext)我无法在没有运行时异常的情况下提交实体要么已经被客户端上下文跟踪,要么没有被客户端上下文跟踪......
-
您是否尝试过使用不同的带有 json 或 httpclient 的客户端?不知道自动生成的wcf客户端代理是否支持patch/delta。
-
正是...我的问题是特定于自动生成的客户端及其派生的
DataServiceContext。我见过使用“手动”构建的帖子正文的示例。同样,上面的示例来自团队自己发布的 CodePlex 上的 Web API 示例应用程序。因此,他们努力展示了如何使用 patch 与 put,但我很困惑这种行为并不像宣传的那样。对于大型实体,为小型属性更新精简有效负载可能很有用。
标签: asp.net-web-api odata