Saltar al contenido

Web API 2: implementación de un PATCH

Basta ya de indagar en otras webs porque has llegado al espacio necesario, contamos con la solución que necesitas y sin complicaciones.

Solución:

Espero que esto ayude a usar Microsoft JsonPatchDocument:

Acción de parche de .Net Core 2.1 en un controlador:

[HttpPatch("id")]
public IActionResult Patch(int id, [FromBody]JsonPatchDocument value)

    try
    
        //nodes collection is an in memory list of nodes for this example
        var result = nodes.FirstOrDefault(n => n.Id == id);
        if (result == null)
        
            return BadRequest();
            
        value.ApplyTo(result, ModelState);//result gets the values from the patch request
        return NoContent();
    
    catch (Exception ex)
    
        return StatusCode(StatusCodes.Status500InternalServerError, ex);
    

Clase de modelo de nodo:

[DataContract(Name ="Node")]
public class Node

    [DataMember(Name = "id")]
    public int Id  get; set; 

    [DataMember(Name = "node_id")]
    public int Node_id  get; set; 

    [DataMember(Name = "name")]
    public string Name  get; set; 

    [DataMember(Name = "full_name")]
    public string Full_name  get; set; 

Un parche JSon válido para actualizar solo las propiedades “full_name” y “node_id” será un array de operaciones como:

[
   "op": "replace", "path": "full_name", "value": "NewNameWithPatch",
   "op": "replace", "path": "node_id", "value": 10
]

Como puede ver, “op” es la operación que le gustaría realizar, la más común es “reemplazar”, que simplemente establecerá el valor existente de esa propiedad para la nueva, pero hay otras:

[
   "op": "test", "path": "property_name", "value": "value" ,
   "op": "remove", "path": "property_name" ,
   "op": "add", "path": "property_name", "value": [ "value1", "value2" ] ,
   "op": "replace", "path": "property_name", "value": 12 ,
   "op": "move", "from": "property_name", "path": "other_property_name" ,
   "op": "copy", "from": "property_name", "path": "other_property_name" 
]

Aquí hay un método de extensiones que construí basado en la especificación Patch (“reemplazar”) en C # usando la reflexión que puede usar para serializar cualquier objeto para realizar una operación Patch (“reemplazar”), también puede pasar la codificación deseada y lo hará devuelve el HttpContent (StringContent) listo para ser enviado a httpClient.PatchAsync (endPoint, httpContent):

public static StringContent ToPatchJsonContent(this object node, Encoding enc = null)

    List patchObjectsCollection = new List();

    foreach (var prop in node.GetType().GetProperties())
    
        var patch = new PatchObject Op = "replace", Path = prop.Name , Value = prop.GetValue(node) ;
        patchObjectsCollection.Add(patch);                
    

    MemoryStream payloadStream = new MemoryStream();
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(patchObjectsCollection.GetType());
    serializer.WriteObject(payloadStream, patchObjectsCollection);
    Encoding encoding = enc ?? Encoding.UTF8;
    var content = new StringContent(Encoding.UTF8.GetString(payloadStream.ToArray()), encoding, "application/json");

    return content;

}

Noté que tt también usa esta clase que creé para serializar el PatchObject usando DataContractJsonSerializer:

[DataContract(Name = "PatchObject")]
class PatchObject

    [DataMember(Name = "op")]
    public string Op  get; set; 
    [DataMember(Name = "path")]
    public string Path  get; set; 
    [DataMember(Name = "value")]
    public object Value  get; set; 

AC # ejemplo de cómo usar el método de extensión e invocar la solicitud de parche usando HttpClient:

    var nodeToPatch = new  Name = "TestPatch", Private = true ;//You can use anonymous type
    HttpContent content = nodeToPatch.ToPatchJsonContent();//Invoke the extension method to serialize the object

    HttpClient httpClient = new HttpClient();
    string endPoint = "https://localhost:44320/api/nodes/1";
    var response = httpClient.PatchAsync(endPoint, content).Result;

Gracias

PATCH Las operaciones no suelen definirse utilizando el mismo modelo que el POST o PUT operaciones exactamente por esa razón: ¿Cómo se diferencia entre un nully un don't change. Desde el IETF:

Sin embargo, con PATCH, la entidad adjunta contiene un conjunto de instrucciones que describen cómo se debe modificar un recurso que reside actualmente en el servidor de origen para producir una nueva versión.

Puedes buscar aquí sus PATCH sugerencia, pero sumarilly es:

[
     "op": "test", "path": "/a/b/c", "value": "foo" ,
     "op": "remove", "path": "/a/b/c" ,
     "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] ,
     "op": "replace", "path": "/a/b/c", "value": 42 ,
     "op": "move", "from": "/a/b/c", "path": "/a/b/d" ,
     "op": "copy", "from": "/a/b/d", "path": "/a/b/e" 
]

La respuesta de @ Tipx está usando PATCH es acertado, pero como probablemente ya haya descubierto, lograrlo en un lenguaje de tipado estático como C # no es un ejercicio trivial.

En el caso de que esté utilizando un PATCH para representar un conjunto de actualizaciones parciales para una única entidad de dominio (por ejemplo, para actualizar el nombre y apellido solo para un contacto con muchas más propiedades), debe hacer algo en la línea de repetir cada instrucción en la solicitud ‘PATCH’ y luego aplicando esa instrucción a una instancia de su clase.

La aplicación de una instrucción individual comprenderá entonces

  • Encontrar la propiedad de la instancia que coincide con el nombre en la instrucción o manejar nombres de propiedad que no esperaba
  • Para una actualización: intentar analizar el valor enviado en el parche en la propiedad de la instancia y manejar el error si, por ejemplo, la propiedad de la instancia es un bool pero la instrucción del parche contiene una fecha
  • Decidir qué hacer con las instrucciones Agregar, ya que no puede agregar nuevas propiedades a una clase C # escrita estáticamente. Un enfoque es decir que Agregar significa “establecer el valor de la propiedad de la instancia solo si el valor existente de la propiedad es null”

Para Web API 2 en el .NET Framework completo, el proyecto JSONPatch github parece intentar proporcionar este código, aunque no parece que haya habido mucho desarrollo en ese repositorio recientemente y el archivo Léame dice:

Este es todavía un proyecto muy temprano, no lo use en producción todavía a menos que comprenda la fuente y no le importe corregir algunos errores;)

Las cosas son más simples en .NET Core, ya que tiene un conjunto de funcionalidades para admitir esto en el Microsoft.AspNetCore.JsonPatch espacio de nombres.

El sitio jsonpatch.com bastante útil también enumera algunas opciones más para Patch en .NET:

  • Asp.Net Core JsonPatch (implementación oficial de Microsoft)
  • Ramone (un marco para consumir servicios REST, incluye una implementación de parche JSON)
  • JsonPatch (agrega compatibilidad con JSON Patch a ASP.NET Web API)
  • Starcounter (motor de aplicaciones en memoria, utiliza JSON Patch con OT para sincronización cliente-servidor)
  • Nancy.JsonPatch (agrega compatibilidad con el parche JSON a NancyFX)
  • Manatee.Json (JSON-todo, incluido el parche JSON)

Necesito agregar esta funcionalidad a un proyecto de Web API 2 existente, así que actualizaré esta respuesta si encuentro algo más que sea útil mientras lo hago.

Sección de Reseñas y Valoraciones

Al final de todo puedes encontrar las críticas de otros desarrolladores, tú aún eres capaz mostrar el tuyo si lo deseas.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *