Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

partial update with asp.net web api

I created a simple todo list application in asp.net mvc 3 with web api and dbContext. ( with backbone and requirejs for the client ) Everything works fine, but i am sort of bothered with the fact that i have to sent the entire model to the server if i check or uncheck a todo item as done. I would like to only sent the "done" field when submitting data.

I should mention that i'm also using the JsonNetFormatter to use JSON.NET as the default Serializer ( explained here: http://blogs.msdn.com/b/henrikn/archive/2012/02/18/using-json-net-with-asp-net-web-api.aspx ).

Currently this is my api controller method to update the model

public HttpResponseMessage Put(Todo todo)
{
    _db.Entry(todo).State = EntityState.Modified;
    _db.SaveChanges();
    return new HttpResponseMessage(HttpStatusCode.NoContent);
}

It takes this as json data

{"content":"Pick up milk","done":false,"id":10}

Off course this works, but it is updating the entire model, it should only update 1 field. I can achieve to only send the changed fields to the server from the browser, but i am not sure what the web api method should look like. I was thinking about doing something with FormCollection but this doesn't seem to work with the web api as it appears to be trying to serialize the submitted formvalues directly to FormCollection type, I get this error.

Cannot deserialize JSON object (i.e. {"name":"value"}) into type 'System.Web.Mvc.FormCollection'.

How can i send a partial update for 1 or more fields from a model to my web api ? I only want to send the updated fields to the server, and from there only update those fields to the database. I certainly do not want to query the database before updating.

like image 998
Willem D'Haeseleer Avatar asked Apr 25 '12 22:04

Willem D'Haeseleer


1 Answers

One approach would be to use a tool called Automapper and configure it so that null values don't overwrite existing ones when mapping Todo objects. For example:

  Mapper.CreateMap<Todo,Todo>()
        .ForMember(d => d.Id, o => o.Ignore())
        .ForAllMembers(mo => mo.Condition(cond => !cond.IsSourceValueNull));  

Then you would just have to map the received object value to the existing one, like this:

  Mapper.Map(todo, item);

Another suggestion would be to use PATCH instead of PUT which is more appropriate to partial updates of resources according to REST.

like image 150
elolos Avatar answered Sep 26 '22 08:09

elolos