2012-04-26 12 views
16

Supongamos que tengo este modeloASP Web API aplicación de parches

public partial class Todo 
{ 
    public int id { get; set; } 
    public string content { get; set; } 
    public bool done { get; set; } 
} 

y yo les enviamos esto como datos JSON a mi controlador como una solicitud de parche. Esta es la acción de activar o desactivar una casilla de verificación. Creo que da a entender que solo quiero enviar eso a mi servidor, y no a todo el modelo.

{ "id":1, "done" : true } 

¿Qué aspecto debe tener mi controlador WebApi para procesar correctamente esta sencilla solicitud de parche json? ¿Debería usar API web para esto, o debería usar un enfoque más estilo rpc con mvc?

parece una cosa muy básica que hacer, pero me parece que no puede hacer las cosas bien! Creo que podría necesitar usar un parámetro diferente en mi método de controlador, pero no estoy seguro.

Gracias por su tiempo.

+0

Puede usar JsonPatch que es compatible con ASP.NET, ASP.NET Core y PCL para Xamarin. https://github.com/KevinDockx/JsonPatch. Un buen artículo se puede encontrar aquí http://benfoster.io/blog/aspnet-core-json-patch-partial-api-updates –

+0

Ese es un problema diferente, creo. Mi modelo no está basado en json. La forma en que la actualización del estado real va a suceder debe depender del implementador. No quiero tener que traducir algunas especificaciones de RFC a una consulta SQL o mutaciones de entidades. –

Respuesta

11

puede encontrar característica Programa En el pre-lanzamiento del paquete Nuget OData: Microsoft.AspNet.WebApi.OData.

información de cómo puede utilizarlo para crear una acción para el manejo de parche se puede encontrar en las actualizaciones parciales (solicitudes parche) sección del blog acerca de OData support in ASP.NET Web API.

+1

Mire esta muestra para hacer parches a través del serializador json.net sin depender de los formatos de conexión oData - https: //aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/DeltaJsonDeserialization/ –

1

API Web ASP.NET parece faltar UpdateModel, TryUpdateModel, etc.

En ASP.NET MVC, se podría utilizar para lograr el efecto deseado. He creado un work item en Web Stack de ASP.NET, que puede votar y si obtiene suficientes votos, se implementará.

12

Cambio del método de parche no cambiar el comportamiento de la API Web de ninguna manera. No hay un mecanismo incorporado para realizar actualizaciones parciales. Una de las razones por las que no hubo un método PATCH durante tanto tiempo es que no existe un tipo de medio omnipresente para aplicar parches a los recursos.

En segundo lugar, usted está pidiendo API web para hacer la serialización de objetos para usted por lo que no solo hay tal concepto de aplicar un objeto parcialmente actualizada. Habría tantas convenciones para acordar, qué significa un valor nulo, qué pasa con un valor vacío, cómo digo "no actualizo este DateTime". ¿Qué pasa con los objetos relacionados, artículos para niños? ¿Cómo se puede eliminar un elemento hijo? A menos que el equipo de CLR implemente algún concepto de un tipo que solo contenga un subconjunto de miembros de otro tipo, las actualizaciones parciales y la serialización de objetos no van a funcionar bien juntas.

Aliostad menciona UpdateModel y eso es posible cuando se actualiza desde un formulario HTML porque el tipo de medio application/x-www-form-urlencoded permite explícitamente un conjunto arbitrario de pares de valores de nombre. No hay una "serialización de objetos" en curso. Es solo una coincidencia de nombres del formulario que coincide con los nombres en el objeto Modelo.

Para mí, creé un nuevo tipo de medio que utilizo para hacer actualizaciones parciales que funcionan como un formulario, pero es más avanzado porque puede manejar datos jerárquicos y mantiene el orden de las actualizaciones.

+0

+1. ¿Puede este formateador de tipo de medios suyo ser incluido en la contribución de la API web? Este es un escenario común y puedo imaginar que tal característica se solicita con frecuencia. – Aliostad

+0

Gracias por su respuesta, ¿cuál sería el enfoque correcto si quisiera actualizar solo un campo de mi modelo (el campo de casilla de verificación 'hecho' en este escenario)? ¿Debo abandonar web api? ¿Cómo puedo hacer esto sin perder la validación de mi modelo? Es difícil creer que una acción tan simple no sea posible con "los últimos tiempos" en las tecnologías asp.net –

+0

He editado mi pregunta para describir mejor el problema. –

0

Solía ​​Microsoft.AspNet.WebApi.OData para mi proyecto y tuve algunos problemas al trabajar con JSON (trabajar con números en mi caso). Además, el paquete OData tiene algunas dependencias que, desde mi punto de vista, son demasiado grandes para una sola función (~ 7MB con todas las dependencias).

Así que desarrollé una biblioteca simple que hace lo que está pidiendo: SimplePatch.

Cómo utilizar

instalar el paquete usando:

Install-Package SimplePatch 

Luego, en su controlador:

[HttpPatch] 
public IHttpActionResult PatchOne(Delta<Todo> todo) 
{ 
    if (todo.TryGetPropertyValue(nameof(Todo.id), out int id)) { 
     // Entity to update (from your datasource) 
     var todoToPatch = Todos.FirstOrDefault(x => x.id == id); 
     if (todoToPatch == null) return BadRequest("Todo not found"); 

     todo.Patch(todoToPatch);  

     // Now todoToPatch is updated with new values    
    } else { 
     return BadRequest(); 
    }  

    return Ok(); 
} 

El apoyo biblioteca de parches masiva también:

[HttpPatch] 
public IHttpActionResult PatchMultiple(DeltaCollection<Todo> todos) 
{ 
    foreach (var todo in todos) 
    { 
     if (todo.TryGetPropertyValue(nameof(Todo.id), out int id)) 
     { 
      // Entity to update (from your datasource) 
      var entityToPatch = Todos.FirstOrDefault(x => x.id == Convert.ToInt32(id)); 
      if (entityToPatch == null) return BadRequest("Todo not found (Id = " + id + ")"); 

      person.Patch(entityToPatch); 
     } 
     else 
     { 
      return BadRequest("Id property not found for a todo"); 
     } 
    } 

    return Ok(); 
} 

Si utiliza Entity Framework, hay que añadir sólo dos líneas de código después de la llamada al método Patch:

entity.Patch(entityToPatch); 

dbContext.Entry(entityToPatch).State = EntityState.Modified; 
dbContext.SaveChanges(); 

Además, puede excluir algunas propiedades que actualizarse cuando se llama al método Patch. Global.asax o Startup.cs

DeltaConfig.Init((cfg) => 
{ 
    cfg.ExcludeProperties<Todo>(x => x.id); 
}); 

Esto es muy útil cuando se está trabajando con una entidad y no desea crear un modelo.

Cuestiones relacionadas