One of the great features of the Microsoft ASP.NET WebAPI OData package (which you can grab as prerelease from Nuget, and which will soon, in next release cycle, become part of Web API core) is a little dynamic proxy object called Delta<T>.

It allows you to perform ridiculously easy mapping of properties between the model obtained from the database and the model passed by the client – thus facilitating all kinds of update scenarios your application may encounter.

Unfortunately, it will not work for you – unless you commit to ODataMediaTypeFormatter and all the extravaganza related to OData. What if you want to use the traditional API formatters, but still leverage on the power of Delta<T>?

Let’s have a look at how you can perform really smooth full (PUT) and partial (PATCH) updates of your resources in Web API.

Introducing Delta

The idea behind Delta<T> is that it acts as a lightweight dynamic proxy between your update source model (or view model or whatever you wish to update with) and the update target. As a consequence you’d use Delta<T> as an input parameter for your resource’s update action (in place of just plain T).

It will track the changed properties and unmodified ones, making sure only the stuff that’s supposed to be updated, gets updated. Delta does that by generating lambda based property setters Action>TEntity,object< and use them to set the properties of your entity.

For example, if you have a CustomerController, your Web API action would have a PUT action that would no longer take a Customer object as an input, but rather a Delta<Customer>.

Let’s write some code.

Adding Delta to your API

Let’s take a simple API as an example. A model:

C#

1

2

3

4

5

6

publicclassTeam{

publicGuidId{get;set;}

publicstringName{get;set;}

publicstringLeague{get;get;}

publicintRating{get;set;}

}

With Delta, a “traditional” Web API controller, with typical CRUD resource operations would now look like this:

As you see, in both cases Delta<T> saves us a lot of effort of tracking which properties to update. The real power of it is visible with the use of HTTP PATCH, as it allows the client to pass incomplete objects, for example:

– PATCH /api/team/33909eaf-56a1-4467-a01a-64b94f10490c

JavaScript

1

2

3

{

"League":"NHL NorthEast"

}

This will partially update the model (only using the property passed by the client).

I will not go into details – since this is not a post about OData – but there are some reasons why you might not want to do that, and want to still use vanilla API with just JsonMediaTypeFormatter. If you choose to go with OData there are a number of other considerations, I recommend you follow Alex James’ great posts to find out more.

What you can do instead – is what we I did , and that is internalize the relevant classes responsible for Delta. I took out some of the existing framework code (5 classes) – from Microsoft ASP.NET WebAPI OData and its System.Web.Http.OData dll. I then removed the dependencies on other helper classes, so that we don’t have to drag along the entire OData stack.

An important thing to note here – the default implementation of Delta<T> was intended to be used with ODataMediaTypeFormatter, since it uses specialized serializers/deserializers and when using it against i.e. the default JsonMediaTypeFormatter, based on JSON.NET it runs into some issues.

I noticed it would choke on:
– int values – because Delta<T> would use Action>TEntity,object< to provide a dynamic property setter. Since JSON.NET would arbitrarily deserialize int into Int64 (long) trying to use an object based (boxed value) lambda to set such value into an int property would throw an InvalidCastException because effectively you are trying to put a long into an int
– Guid values – again, since they would come out of JSON.NET as string and the generic lambda setter would be trying to set a string into a Guid property

I added code to mitigate these errors. There might be more similar issues like this – this is a very experimental exercise after all (at some point, probably requires a nice map of types), but it ends up working nicely for the simple examples I’ve been running.

You can get all the required classes from this Gist, and simply copy them over to your solution. As mentioned, the code comes from ASP.NET Web API OData, just been slightly modified to remove external dependencies and fix some errors.

This way you can start using/experimenting with Delta<T> with plain old JsonMediaTypeFormatter. Oh and one final thing, this is purely experimental!

This is awesome. Have you done anything with bulk updating/patching? I have to do that for my app so I did it one way, I have no idea what the “proper” way to do it is (since this is an AJAX app).

If you have, you should write about how you did it. I basically created a “changeset” view model with the object ID and the properties I needed to change. From this article, it seems like I could replace that with an IEnumerable < Delta > instead.

In my case, I am bulk updating tags… so adding tags, removing tags, from entities. With EF it requires some work to prevent new tags being INSERT’d twice (since they have no ID yet).

http://www.strathweb.com/ Filip W

Thanks man.

I only noticed this could work *without* OData 2 days ago; added it to a project at work (to updated some text-based properties – we have inline editor on a page and each property gets saved automatically on “Enter” key press) and it worked with basic strings etc.

Then I noticed some type conversion issues – since the generic setter uses “object” as a common denominator and when unwrapped from JSON these may not always match with the CLR model – like I mentioned int becomes long and Guid becomes string. Some other things like will probably come up but I’m sure these can be easily mitigated and this could be used safely, and not even for the web – think for example passing objects from service->repository and so on.

http://twitter.com/roysvork Pete Smith

I am having trouble getting this to work… could I ask if you could take a look at my question here when you have a chance?

This is exactly the code I needed for my application (I am using DTO with Web Api 2 & JSON) and I have crow-barred into my project OK.
The main issue I am having is that alot of the properties of the entities I am dealing with are of type Nullable and the code in TrySetPropertyValue rejects this type because it is not primitive.
I successfully wrote an extension method to detect if the underlying type of the Nullable is primitive but now the code falls over when using the setter method of the CompiledPropertyAccessor.
I have not much experience of building Lambda methods & I was hoping someone would be able to help with this.

I prefer that you should rename the namespace (at-least) because if for some reason the ODATA dll loads in appdomain(e.g, third party library reference the ODATA.dll, etc) then you end-up with error, The type X exists both in A.dll and B.dll

This seems like a really cool package which could have a lot of uses. I’d be especially interested to look at how it could be used in an Event Sourcing architecture, ie serializing an ordered list of these deltas…

I have been trying to use this, but the Patch method is not being invoked, and I am getting error, apparently from the router: “Method may only be called on a Type for which Type.IsGenericParameter is true.”

@fillip: Have you been able to get this to work with WebAPI 2. Basically I installed the OData nuget pkg for WebAPI since I need ODataQueryOptions in my GET actions and used your Delta from the GIST. Even for simple POCO types having string properties, I’m getting nulls and the json payload I’m posting is not getting mapped to the Delta. Not sure if the Newtonsoft.Json package (I’m on 6.0.7) that is contributing to this.
Any insights as to what could be causing this. If it helps I can upload a sample repro app.

Abhijeet

@fillip: Have you been able to get this to work with WebAPI 2. Basically I installed the OData nuget pkg for WebAPI since I need ODataQueryOptions in my GET actions and used your Delta from the GIST. Even for simple POCO types having string properties, I’m getting nulls and the json payload I’m posting is not getting mapped to the Delta. Not sure if the Newtonsoft.Json package (I’m on 6.0.7) that is contributing to this.
Any insights as to what could be causing this. If it helps I can upload a sample repro app.