JsonPatch v ASP.NET Core web API

Dykstra a Kirka Larkin

tento článek vysvětluje, jak zpracovat žádosti o opravu JSON ve ASP.NET Core webovém rozhraní API.

Instalace balíčku

Pokud chcete ve své aplikaci povolit podporu oprav JSON, proveďte následující kroky:

  1. nainstalujte Microsoft.AspNetCore.Mvc.NewtonsoftJson balíček NuGet.

  2. Aktualizujte metodu projektu Startup.ConfigureServices pro volání AddNewtonsoftJson . Například:

    services
        .AddControllersWithViews()
        .AddNewtonsoftJson();
    

AddNewtonsoftJson je kompatibilní s metodami registrace služby MVC:

Oprava JSON, AddNewtonsoftJson a System.Text.Js

AddNewtonsoftJson nahradí System.Text.Json vstupní a výstupní formátovací moduly používané pro formátování veškerého obsahu JSON. Chcete-li přidat podporu pro opravu JSON pomocí příkazu Newtonsoft.Json , zatímco ostatní formátovací moduly zůstaly beze změny, aktualizujte Startup.ConfigureServices metodu projektu následujícím způsobem:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.InputFormatters.Insert(0, GetJsonPatchInputFormatter());
    });
}

private static NewtonsoftJsonPatchInputFormatter GetJsonPatchInputFormatter()
{
    var builder = new ServiceCollection()
        .AddLogging()
        .AddMvc()
        .AddNewtonsoftJson()
        .Services.BuildServiceProvider();

    return builder
        .GetRequiredService<IOptions<MvcOptions>>()
        .Value
        .InputFormatters
        .OfType<NewtonsoftJsonPatchInputFormatter>()
        .First();
}

Předchozí kód vyžaduje Microsoft.AspNetCore.Mvc.NewtonsoftJson balíček a následující using příkazy:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using System.Linq;

Použijte Newtonsoft.Json.JsonConvert.SerializeObject metodu k serializaci JsonPatchDocument.

Oprava metody požadavku HTTP

Metody PUT a patch se používají k aktualizaci existujícího prostředku. Rozdíl mezi nimi spočívá v tom, že PUT nahradí celý prostředek, zatímco PATCH zadává pouze změny.

Oprava JSON

Oprava JSON je formát pro určení aktualizací, které se mají použít u prostředku. Dokument opravy JSON má pole operací. Každá operace identifikuje konkrétní typ změny. Příklady takových změn zahrnují přidání prvku pole nebo nahrazení hodnoty vlastnosti.

Následující dokumenty JSON například reprezentují prostředek, dokument opravy JSON pro daný prostředek a výsledek použití operací opravy.

Příklad prostředku

{
  "customerName": "John",
  "orders": [
    {
      "orderName": "Order0",
      "orderType": null
    },
    {
      "orderName": "Order1",
      "orderType": null
    }
  ]
}

Příklad opravy JSON

[
  {
    "op": "add",
    "path": "/customerName",
    "value": "Barry"
  },
  {
    "op": "add",
    "path": "/orders/-",
    "value": {
      "orderName": "Order2",
      "orderType": null
    }
  }
]

V předchozím fragmentu kódu JSON:

  • opVlastnost určuje typ operace.
  • pathVlastnost určuje prvek, který se má aktualizovat.
  • valueVlastnost poskytuje novou hodnotu.

Prostředek po opravě

Toto je prostředek po použití předchozího dokumentu opravy JSON:

{
  "customerName": "Barry",
  "orders": [
    {
      "orderName": "Order0",
      "orderType": null
    },
    {
      "orderName": "Order1",
      "orderType": null
    },
    {
      "orderName": "Order2",
      "orderType": null
    }
  ]
}

Změny provedené při použití dokumentu opravy JSON na prostředek jsou atomické. Pokud se některá operace v seznamu nezdařila, nebude použita žádná operace v seznamu.

Syntaxe cesty

Vlastnost path objektu operace má lomítka mezi úrovněmi. Například, "/address/zipCode".

Indexy založené na nule slouží k určení prvků pole. První prvek addresses pole by byl na /addresses/0 . Na add konec pole použijte spojovník ( - ) místo čísla indexu: /addresses/- .

Operace

V následující tabulce jsou uvedeny podporované operace, jak je definováno ve specifikaci opravy JSON:

Operace Poznámky
add Přidejte vlastnost nebo prvek pole. Pro existující vlastnost: nastavte hodnotu.
remove Odebere vlastnost nebo prvek pole.
replace Stejné jako remove následováno ve add stejném umístění.
move Stejné jako remove u zdroje, po kterém následuje add k cíli, pomocí hodnoty ze zdroje.
copy Stejné jako add cíl pomocí hodnoty ze zdroje.
test Vrátí stavový kód úspěšného zpracování, pokud je zadána hodnota at path value .

Oprava JSON v ASP.NET Core

implementace opravy JSON ASP.NET Core je k dispozici v balíčku Microsoft.AspNetCore.Jsaktualizace NuGet.

Kód metody akce

V řadiči rozhraní API metoda Action pro opravu JSON:

  • Je označen HttpPatch atributem.
  • Akceptuje JsonPatchDocument<T> , obvykle s [FromBody] .
  • ApplyToZměny se projeví v dokumentu opravy.

Tady je příklad:

[HttpPatch]
public IActionResult JsonPatchWithModelState(
    [FromBody] JsonPatchDocument<Customer> patchDoc)
{
    if (patchDoc != null)
    {
        var customer = CreateCustomer();

        patchDoc.ApplyTo(customer, ModelState);

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        return new ObjectResult(customer);
    }
    else
    {
        return BadRequest(ModelState);
    }
}

Tento kód z ukázkové aplikace funguje s následujícím Customer modelem:

public class Customer
{
    public string CustomerName { get; set; }
    public List<Order> Orders { get; set; }
}
public class Order
{
    public string OrderName { get; set; }
    public string OrderType { get; set; }
}

Ukázková akce metody:

  • Vytvoří Customer .
  • Aplikuje opravu.
  • Vrátí výsledek v těle odpovědi.

V reálné aplikaci kód načetl data z úložiště, jako je databáze, a po použití opravy aktualizuje databázi.

Stav modelu

Předchozí příklad metody volá přetížení ApplyTo , které přijímá stav modelu jako jeden z jeho parametrů. Pomocí této možnosti můžete získat chybové zprávy v odpovědích. Následující příklad ukazuje tělo 400 chybné odpovědi žádosti pro test operaci:

{
    "Customer": [
        "The current value 'John' at path 'customerName' is not equal to the test value 'Nancy'."
    ]
}

Dynamické objekty

Následující příklad metody akce ukazuje, jak použít opravu na dynamický objekt:

[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
    dynamic obj = new ExpandoObject();
    patch.ApplyTo(obj);

    return Ok(obj);
}

Operace přidání

  • pathOdkazuje-li na prvek pole: vloží nový prvek před první, který je určen parametrem path .
  • Pokud path odkazuje na vlastnost: nastaví hodnotu vlastnosti.
  • Pokud path odkazuje na neexistující umístění:
    • Pokud je prostředek k opravě dynamický objekt: Přidá vlastnost.
    • Pokud je prostředek k opravě statický objekt: požadavek se nezdařil.

Následující ukázkový dokument opravy nastavuje hodnotu CustomerName a přidá Order objekt na konec Orders pole.

[
  {
    "op": "add",
    "path": "/customerName",
    "value": "Barry"
  },
  {
    "op": "add",
    "path": "/orders/-",
    "value": {
      "orderName": "Order2",
      "orderType": null
    }
  }
]

Operace Remove

  • Pokud path odkazuje na element pole: Odebere prvek.
  • Pokud path odkazuje na vlastnost:
    • Pokud je prostředek k opravě dynamický objekt: Odebere vlastnost.
    • Pokud je prostředek pro opravu statickým objektem:
      • Pokud je vlastnost Nullable: nastaví ji na null.
      • Pokud vlastnost nemůže mít hodnotu null, nastaví ji na default<T> .

Následující ukázkový dokument opravy se nastaví CustomerName na hodnotu null a odstraní Orders[0] :

[
  {
    "op": "remove",
    "path": "/customerName"
  },
  {
    "op": "remove",
    "path": "/orders/0"
  }
]

Operace Replace

Tato operace je funkčně stejná jako remove následováno add .

Následující ukázkový dokument opravy nastavuje hodnotu CustomerName a nahrazuje Orders[0] novým Order objektem:

[
  {
    "op": "replace",
    "path": "/customerName",
    "value": "Barry"
  },
  {
    "op": "replace",
    "path": "/orders/0",
    "value": {
      "orderName": "Order2",
      "orderType": null
    }
  }
]

Operace přesunutí

  • Pokud path odkazuje na element pole: zkopíruje from element do umístění path elementu a potom spustí remove operaci na from elementu.
  • Pokud path odkazuje na vlastnost: zkopíruje hodnotu from vlastnosti na path vlastnost a potom spustí remove operaci pro from vlastnost.
  • Pokud path odkazuje na neexistující vlastnost:
    • Pokud je prostředek k opravě statický objekt: požadavek se nezdařil.
    • Pokud je prostředek pro opravu dynamický objekt: zkopíruje from vlastnost do umístění označeného path a potom spustí remove operaci pro from vlastnost.

Následující ukázkový dokument opravy:

  • Zkopíruje hodnotu Orders[0].OrderName do CustomerName .
  • Nastaví Orders[0].OrderName na hodnotu null.
  • Přesune Orders[1] se na dřív Orders[0] .
[
  {
    "op": "move",
    "from": "/orders/0/orderName",
    "path": "/customerName"
  },
  {
    "op": "move",
    "from": "/orders/1",
    "path": "/orders/0"
  }
]

Operace kopírování

Tato operace je funkčně stejná jako move operace bez posledního remove kroku.

Následující ukázkový dokument opravy:

  • Zkopíruje hodnotu Orders[0].OrderName do CustomerName .
  • Vloží kopii Orders[1] před Orders[0] .
[
  {
    "op": "copy",
    "from": "/orders/0/orderName",
    "path": "/customerName"
  },
  {
    "op": "copy",
    "from": "/orders/1",
    "path": "/orders/0"
  }
]

Operace testu

Pokud hodnota v umístění, která je uvedena v path , se liší od hodnoty uvedené v value , požadavek se nezdařil. V takovém případě celá žádost o opravu selže i v případě, že všechny ostatní operace v dokumentu opravy by jinak uspěly.

Tato test operace se běžně používá k tomu, aby se zabránilo aktualizaci v případě konfliktu souběžnosti.

Následující ukázkový dokument opravy nemá žádný vliv, pokud je původní hodnota CustomerName "Jan", protože test se nezdařil:

[
  {
    "op": "test",
    "path": "/customerName",
    "value": "Nancy"
  },
  {
    "op": "add",
    "path": "/customerName",
    "value": "Barry"
  }
]

Získání kódu

Zobrazit nebo stáhnout vzorový kód. (Stažení).

Pokud chcete ukázku otestovat, spusťte aplikaci a odešlete požadavky HTTP s následujícím nastavením:

  • Adresa URL http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate
  • Metoda HTTP: PATCH
  • Hlaviček Content-Type: application/json-patch+json
  • Tělo: Zkopírujte a vložte jeden ze vzorků dokumentů opravy JSON ze složky projektu JSON .

Další zdroje informací

tento článek vysvětluje, jak zpracovat žádosti o opravu JSON ve ASP.NET Core webovém rozhraní API.

Oprava metody požadavku HTTP

Metody PUT a patch se používají k aktualizaci existujícího prostředku. Rozdíl mezi nimi spočívá v tom, že PUT nahradí celý prostředek, zatímco PATCH zadává pouze změny.

Oprava JSON

Oprava JSON je formát pro určení aktualizací, které se mají použít u prostředku. Dokument opravy JSON má pole operací. Každá operace identifikuje konkrétní typ změny, jako je například přidání prvku pole nebo nahrazení hodnoty vlastnosti.

Následující dokumenty JSON například reprezentují prostředek, dokument opravy JSON pro daný prostředek a výsledek použití operací opravy.

Příklad prostředku

{
  "customerName": "John",
  "orders": [
    {
      "orderName": "Order0",
      "orderType": null
    },
    {
      "orderName": "Order1",
      "orderType": null
    }
  ]
}

Příklad opravy JSON

[
  {
    "op": "add",
    "path": "/customerName",
    "value": "Barry"
  },
  {
    "op": "add",
    "path": "/orders/-",
    "value": {
      "orderName": "Order2",
      "orderType": null
    }
  }
]

V předchozím fragmentu kódu JSON:

  • opVlastnost určuje typ operace.
  • pathVlastnost určuje prvek, který se má aktualizovat.
  • valueVlastnost poskytuje novou hodnotu.

Prostředek po opravě

Toto je prostředek po použití předchozího dokumentu opravy JSON:

{
  "customerName": "Barry",
  "orders": [
    {
      "orderName": "Order0",
      "orderType": null
    },
    {
      "orderName": "Order1",
      "orderType": null
    },
    {
      "orderName": "Order2",
      "orderType": null
    }
  ]
}

Změny provedené při použití dokumentu opravy JSON na prostředek jsou atomické: Pokud se některá operace v seznamu nezdařila, nepoužije se žádná operace v seznamu.

Syntaxe cesty

Vlastnost path objektu operace má lomítka mezi úrovněmi. Například, "/address/zipCode".

Indexy založené na nule slouží k určení prvků pole. První prvek addresses pole by byl na /addresses/0 . Na add konec pole, použijte spojovník (-) místo čísla indexu: /addresses/- .

Operace

V následující tabulce jsou uvedeny podporované operace, jak je definováno ve specifikaci opravy JSON:

Operace Poznámky
add Přidejte vlastnost nebo prvek pole. Pro existující vlastnost: nastavte hodnotu.
remove Odebere vlastnost nebo prvek pole.
replace Stejné jako remove následováno ve add stejném umístění.
move Stejné jako remove u zdroje, po kterém následuje add k cíli, pomocí hodnoty ze zdroje.
copy Stejné jako add cíl pomocí hodnoty ze zdroje.
test Vrátí stavový kód úspěšného zpracování, pokud je zadána hodnota at path value .

JsonPatch v ASP.NET Core

implementace opravy JSON ASP.NET Core je k dispozici v balíčku Microsoft.AspNetCore.Jsaktualizace NuGet. Balíček je zahrnutý v Microsoft.AspnetCore.app Metapackage.

Kód metody akce

V řadiči rozhraní API metoda Action pro opravu JSON:

  • Je označen HttpPatch atributem.
  • Akceptuje JsonPatchDocument<T> , obvykle s [FromBody] .
  • ApplyToZměny se projeví v dokumentu opravy.

Tady je příklad:

[HttpPatch]
public IActionResult JsonPatchWithModelState(
    [FromBody] JsonPatchDocument<Customer> patchDoc)
{
    if (patchDoc != null)
    {
        var customer = CreateCustomer();

        patchDoc.ApplyTo(customer, ModelState);

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        return new ObjectResult(customer);
    }
    else
    {
        return BadRequest(ModelState);
    }
}

Tento kód z ukázkové aplikace funguje s následujícím Customer modelem.

public class Customer
{
    public string CustomerName { get; set; }
    public List<Order> Orders { get; set; }
}
public class Order
{
    public string OrderName { get; set; }
    public string OrderType { get; set; }
}

Ukázková akce metody:

  • Vytvoří Customer .
  • Aplikuje opravu.
  • Vrátí výsledek v těle odpovědi.

V reálné aplikaci kód načetl data z úložiště, jako je databáze, a po použití opravy aktualizuje databázi.

Stav modelu

Předchozí příklad metody volá přetížení ApplyTo , které přijímá stav modelu jako jeden z jeho parametrů. Pomocí této možnosti můžete získat chybové zprávy v odpovědích. Následující příklad ukazuje tělo 400 chybné odpovědi žádosti pro test operaci:

{
    "Customer": [
        "The current value 'John' at path 'customerName' is not equal to the test value 'Nancy'."
    ]
}

Dynamické objekty

Následující příklad metody akce ukazuje, jak použít opravu na dynamický objekt.

[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
    dynamic obj = new ExpandoObject();
    patch.ApplyTo(obj);

    return Ok(obj);
}

Operace přidání

  • pathOdkazuje-li na prvek pole: vloží nový prvek před první, který je určen parametrem path .
  • Pokud path odkazuje na vlastnost: nastaví hodnotu vlastnosti.
  • Pokud path odkazuje na neexistující umístění:
    • Pokud je prostředek k opravě dynamický objekt: Přidá vlastnost.
    • Pokud je prostředek k opravě statický objekt: požadavek se nezdařil.

Následující ukázkový dokument opravy nastavuje hodnotu CustomerName a přidá Order objekt na konec Orders pole.

[
  {
    "op": "add",
    "path": "/customerName",
    "value": "Barry"
  },
  {
    "op": "add",
    "path": "/orders/-",
    "value": {
      "orderName": "Order2",
      "orderType": null
    }
  }
]

Operace Remove

  • Pokud path odkazuje na element pole: Odebere prvek.
  • Pokud path odkazuje na vlastnost:
    • Pokud je prostředek k opravě dynamický objekt: Odebere vlastnost.
    • Pokud je prostředek pro opravu statickým objektem:
      • Pokud je vlastnost Nullable: nastaví ji na null.
      • Pokud vlastnost nemůže mít hodnotu null, nastaví ji na default<T> .

Následující ukázkový dokument opravy se nastaví CustomerName na hodnotu null a odstraní Orders[0] .

[
  {
    "op": "remove",
    "path": "/customerName"
  },
  {
    "op": "remove",
    "path": "/orders/0"
  }
]

Operace Replace

Tato operace je funkčně stejná jako remove následováno add .

Následující ukázkový dokument opravy nastavuje hodnotu CustomerName a nahrazuje Orders[0] novým Order objektem.

[
  {
    "op": "replace",
    "path": "/customerName",
    "value": "Barry"
  },
  {
    "op": "replace",
    "path": "/orders/0",
    "value": {
      "orderName": "Order2",
      "orderType": null
    }
  }
]

Operace přesunutí

  • pathOdkazuje-li na prvek pole: zkopíruje prvek do umístění elementu a poté spustí operaci na from path remove from elementu .
  • Pokud odkazuje na vlastnost: zkopíruje hodnotu vlastnosti do vlastnosti a pak path from spustí operaci s path remove from vlastností .
  • Pokud path odkazuje na neexistující vlastnost:
    • Pokud je prostředek, který se má opravovat, statickým objektem: požadavek selže.
    • Pokud je prostředek, který se má opravovat, dynamický objekt: zkopíruje vlastnost do umístění označeného příkazem from , spustí operaci s path remove from vlastností .

Následující ukázkový dokument opravy:

  • Zkopíruje hodnotu do Orders[0].OrderName CustomerName .
  • Nastaví Orders[0].OrderName hodnotu null.
  • Přesune Orders[1] se na před Orders[0] .
[
  {
    "op": "move",
    "from": "/orders/0/orderName",
    "path": "/customerName"
  },
  {
    "op": "move",
    "from": "/orders/1",
    "path": "/orders/0"
  }
]

Operace kopírování

Tato operace je funkčně stejná jako move operace bez posledního remove kroku.

Následující ukázkový dokument opravy:

  • Zkopíruje hodnotu do Orders[0].OrderName CustomerName .
  • Vloží kopii před Orders[1] Orders[0] .
[
  {
    "op": "copy",
    "from": "/orders/0/orderName",
    "path": "/customerName"
  },
  {
    "op": "copy",
    "from": "/orders/1",
    "path": "/orders/0"
  }
]

Testovací operace

Pokud se hodnota v umístění označeném liší od hodnoty path zadané v value , požadavek selže. V takovém případě celý požadavek PATCH selže i v případě, že by všechny ostatní operace v dokumentu opravy jinak uspěly.

Tato operace se běžně používá k tomu, aby se zabránilo aktualizaci v případě konfliktu test souběžnosti.

Následující ukázkový dokument opravy nemá žádný vliv, pokud je počáteční hodnota CustomerName "John", protože test selže:

[
  {
    "op": "test",
    "path": "/customerName",
    "value": "Nancy"
  },
  {
    "op": "add",
    "path": "/customerName",
    "value": "Barry"
  }
]

Získání kódu

Zobrazení nebo stažení ukázkového kódu. (Jak stáhnout).

Pokud chcete ukázku otestovat, spusťte aplikaci a odešlete požadavky HTTP s následujícím nastavením:

  • Adresu url: http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate
  • Metoda HTTP: PATCH
  • Záhlaví: Content-Type: application/json-patch+json
  • Text: Zkopírujte a vložte jednu z ukázek dokumentu opravy JSON ze složky projektu JSON.

Další zdroje informací