Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to call patch from an OData client in Web Api 2

Following the OData samples created by the web api team, my controller has the following for supporting Patch:

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);
}

and using the auto-generated client (derived from DataServiceContext), I submit a patch request like this:

var foo = svcContainer.Foos.Where (f => f.Id == 1).SingleOrDefault();
foo.Description = "Updated Description";
svcContainer.UpdateObject(foo);
svcContainer.SaveChanges(SaveChangesOptions.PatchOnUpdate);

However, tracing the call in fiddler, I see that all other properties of Foo are serialized and sent to the service. Is that the correct behavior? I expected only the Id and Description to be sent over the wire. Also, if I debug the service method and call

GetChangedPropertyNames on item, all its property names are returned.

Should I be creating some sort of Delta instance on the client?

I understand the disconnected nature of the service and thus the service side does not have a context for tracking changes, but it seems to me the api team added support for patch for a reason, so I'd like to know if the client ought to be invoking the update in a different manner.

Update

The link YiDing provided explains how to create a true PATCH request from the client (using the Microsoft.OData.Client.DataServiceContext created by the Microsoft.OData.Client 6.2.0 and above. For convenience, here is the code snippet:

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

The DataServiceCollection implements property tracking, and using this pattern, only the updated properties are sent to the service. Without using DataServiceCollection and simply using

svcContainer.UpdateObject(foo);
svcContainer.SaveChanges();

all properties are still sent over the wire despite documentation to the contrary, at least as of Microsoft.OData.Client 6.7.0

like image 288
mdisibio Avatar asked Jan 28 '14 17:01

mdisibio


1 Answers

The client side property tracking is now supported from Microsoft.OData.Client version 6.2.0. It will detect only the modified properties of an entity and send the update request as PATCH instead of PUT to meet the requirement of your scenario. Please refer to this blog post for more details: https://devblogs.microsoft.com/odata/tutorial-sample-client-property-tracking-for-patch/

like image 137
Yi Ding - MSFT Avatar answered Sep 25 '22 07:09

Yi Ding - MSFT