2012-04-25 35 views
8

Creé una aplicación de lista de cosas pendientes en asp.net mvc 3 con web api y dbContext. (con backbone y requirejs para el cliente) Todo funciona bien, pero estoy algo molesto con el hecho de que tengo que enviar todo el modelo al servidor si marque o desmarque una tarea pendiente como completada. Me gustaría enviar solo el campo "hecho" al enviar datos.actualización parcial con asp.net web api

Debo mencionar que también estoy usando JsonNetFormatter para usar JSON.NET como el serializador predeterminado (explicado aquí: http://blogs.msdn.com/b/henrikn/archive/2012/02/18/using-json-net-with-asp-net-web-api.aspx).

Actualmente este es mi método de controlador de API para actualizar el modelo

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

Toma esto como datos JSON

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

¡Por supuesto que esto funciona, pero es la actualización de todo el modelo, lo que debería solo actualiza 1 campo. Solo puedo enviar los campos modificados al servidor desde el navegador, pero no estoy seguro de cómo debería ser el método de la API web. Estaba pensando en hacer algo con FormCollection, pero parece que esto no funciona con la API web, ya que parece tratar de serializar los valores de formulario enviados directamente al tipo FormCollection. Recibo este error.

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

¿Cómo puedo enviar una actualización parcial para 1 o más campos de un modelo a mi API web? Solo quiero enviar los campos actualizados al servidor, y desde allí solo actualizar esos campos a la base de datos. Ciertamente no quiero consultar la base de datos antes de actualizar.

Respuesta

2

Un enfoque sería utilizar una herramienta llamada Automapper y configúrelo para que los valores nulos no sobrescriban los existentes al asignar objetos Todo. Por ejemplo:

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

A continuación, sólo tendría que asignar el valor del objeto recibido a la ya existente, así:

Mapper.Map(todo, item); 

Otra sugerencia sería que el uso del parche en lugar de PUT que es more appropriate to partial updates of resources according to REST.

+3

No se ha vendido en este. ¿Qué sucede si quiere establecer un campo nulo? –

+2

No podrá determinar si el valor nulo fue establecido por el remitente o si simplemente fue establecido por el hecho de que se omitió un campo. En este caso, recomendaría usar el verbo PATCH en su lugar. – elolos

-3

Es necesario consultar el objeto original a partir de la base de datos, establecer sus propiedades & llamada la _db.SaveChange()

public HttpResponseMessage Put(Todo todo){ 
var item = _db.Todo.First(i => i.id = todo.id); 
item.Content = todo.Content; 
item.Done = todo.Done; 
_db.SaveChanges(); 
return new HttpResponseMessage<Todo>(HttpStatusCode.Accepted); 
} 

Ref .: http://msdn.microsoft.com/en-us/library/dd456854.aspx

+7

Esto no responde a la pregunta –