Sdílet prostřednictvím


JsonPatch ve webovém rozhraní API ASP.NET Core

Tento článek vysvětluje, jak zpracovávat požadavky opravy JSON ve webovém rozhraní API ASP.NET Core.

Instalace balíčku

Podpora oprav JSON ve webovém rozhraní API ASP.NET Core je založená a Newtonsoft.Json vyžaduje Microsoft.AspNetCore.Mvc.NewtonsoftJson balíček NuGet. Povolení podpory oprav JSON:

  • Microsoft.AspNetCore.Mvc.NewtonsoftJson Nainstalujte balíček NuGet.

  • Zavolejte AddNewtonsoftJson. Příklad:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddControllers()
        .AddNewtonsoftJson();
    
    var app = builder.Build();
    
    app.UseHttpsRedirection();
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();
    

AddNewtonsoftJson nahrazuje výchozí System.Text.Jsonvstupní a výstupní formátovací moduly založené na formátu všech souborů JSON. Tato metoda rozšíření je kompatibilní s následujícími metodami registrace služby MVC:

JsonPatch vyžaduje nastavení hlavičky Content-Type na application/json-patch+json.

Přidání podpory pro opravu JSON při použití System.Text.Json

Vstupní System.Text.Jsonformátovací modul založený na formátu JSON nepodporuje opravu JSON. Pokud chcete přidat podporu pro opravu JSON pomocí Newtonsoft.Json, zatímco ostatní vstupní a výstupní formátovací moduly zůstanou beze změny:

  • Microsoft.AspNetCore.Mvc.NewtonsoftJson Nainstalujte balíček NuGet.

  • Aktualizace Program.cs:

    using JsonPatchSample;
    using Microsoft.AspNetCore.Mvc.Formatters;
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddControllers(options =>
    {
        options.InputFormatters.Insert(0, MyJPIF.GetJsonPatchInputFormatter());
    });
    
    var app = builder.Build();
    
    app.UseHttpsRedirection();
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();
    
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Formatters;
    using Microsoft.Extensions.Options;
    
    namespace JsonPatchSample;
    
    public static class MyJPIF
    {
        public 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 vytvoří instanci NewtonsoftJsonPatchInputFormatter a vloží ji jako první položku v kolekci MvcOptions.InputFormatters . Toto pořadí registrace zajišťuje, že:

  • NewtonsoftJsonPatchInputFormatter zpracovává žádosti o opravu JSON.
  • System.Text.JsonStávající vstupní a formátovací moduly zpracovávají všechny ostatní požadavky a odpovědi JSON.

Newtonsoft.Json.JsonConvert.SerializeObject Použití metody serializace JsonPatchDocument.

Metoda požadavku HTTP PATCH

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

Oprava JSON

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

Například následující dokumenty JSON představují prostředek, dokument opravy JSON pro prostředek a výsledek použití operací Patch.

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:

  • Vlastnost op označuje typ operace.
  • Vlastnost path označuje prvek, který se má aktualizovat.
  • Vlastnost value poskytuje novou hodnotu.

Prostředek po opravě

Tady 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é použitím dokumentu opravy JSON na prostředek jsou atomické. Pokud jakákoli operace v seznamu selže, nepoužije se žádná operace v seznamu.

Syntaxe cesty

Vlastnost cesty 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 pole addresses by byl na /addresses/0. Chcete-li add na konec pole, použijte místo čísla /addresses/-indexu spojovník (-) .

Operace

Následující tabulka uvádí podporované operace definované ve specifikaci opravy JSON:

Operace Notes
add Přidejte vlastnost nebo prvek pole. Pro existující vlastnost: nastavte hodnotu.
remove Odeberte vlastnost nebo prvek pole.
replace Stejné jako remove následované add na stejném místě.
move Stejné jako remove ze zdroje, za nímž následuje add cíl s použitím hodnoty ze zdroje.
copy Stejné jako add cíl s použitím hodnoty ze zdroje.
test Vrátí stavový kód úspěchu, pokud hodnota at path = poskytnuta value.

Oprava JSON v ASP.NET Core

Základní implementace opravy JSON ASP.NET je k dispozici v balíčku NuGet Microsoft.AspNetCore.JsonPatch .

Kód metody akce

V kontroleru rozhraní API metoda akce pro opravu JSON:

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:

namespace JsonPatchSample.Models;

public class Customer
{
    public string? CustomerName { get; set; }
    public List<Order>? Orders { get; set; }
}
namespace JsonPatchSample.Models;

public class Order
{
    public string OrderName { get; set; }
    public string OrderType { get; set; }
}

Ukázková metoda akce:

  • Vytvoří .Customer
  • Použije opravu.
  • Vrátí výsledek v textu odpovědi.

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

Stav modelu

Předchozí příklad metody akce volá přetížení ApplyTo , které přebírá stav modelu jako jeden z jeho parametrů. Pomocí této možnosti můžete v odpovědích zobrazit chybové zprávy. Následující příklad ukazuje text odpovědi 400 Chybný požadavek pro test operaci:

{
  "Customer": [
    "The current value 'John' at path 'customerName' != 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í

  • Pokud path odkazuje na prvek pole: vloží nový prvek před prvek určený 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ým objektem: přidá vlastnost.
    • Pokud je prostředek, který se má opravit, statický objekt: požadavek selže.

Následující ukázkový dokument opravy nastaví 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 odebrání

  • Pokud path odkazuje na prvek pole: odebere prvek.
  • Pokud path odkazuje na vlastnost:
    • Pokud je prostředek k opravě dynamickým objektem: odebere vlastnost.
    • Pokud je prostředek k opravě statický objekt:
      • Pokud je vlastnost nullable: nastaví ji na hodnotu null.
      • Pokud vlastnost není nullable, nastaví ji na default<T>.

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

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

Operace nahrazení

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

Následující ukázkový dokument opravy nastaví hodnotu CustomerName a nahradí 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 prvek pole: zkopíruje from element do umístění elementu path , pak spustí remove operaci prvku from .
  • Pokud path odkazuje na vlastnost: zkopíruje hodnotu from vlastnosti do path vlastnosti, pak spustí remove operaci vlastnosti from .
  • Pokud path odkazuje na neexistující vlastnost:
    • Pokud je prostředek, který se má opravit, statický objekt: požadavek selže.
    • Pokud prostředek k opravě je dynamický objekt: zkopíruje from vlastnost do umístění označeného path, pak spustí remove operaci s 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řejde Orders[1] 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 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"
  }
]

Testovací operace

Pokud se hodnota v umístění označeném path hodnotou liší od hodnoty 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 proběhly úspěšně.

Operace test se běžně používá k zabránění aktualizaci, když dojde ke konfliktu 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í vzorového kódu (postup stahování).

Ukázku otestujete spuštěním aplikace a odesláním požadavků HTTP s následujícím nastavením:

  • 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ší materiály

Tento článek vysvětluje, jak zpracovávat požadavky opravy JSON ve webovém rozhraní API ASP.NET Core.

Instalace balíčku

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

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

  2. Aktualizujte metodu Startup.ConfigureServices projektu tak, aby volala AddNewtonsoftJson. Příklad:

    services
        .AddControllersWithViews()
        .AddNewtonsoftJson();
    

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

Oprava JSON, AddNewtonsoftJson a System.Text.Json

AddNewtonsoftJson nahrazuje vstupní a výstupní formátovací moduly System.Text.Jsonzaložené na formátech všech souborů JSON. Pokud chcete přidat podporu pro opravu JSON pomocí Newtonsoft.Json, zatímco ostatní formátovací moduly zůstanou beze změny, aktualizujte metodu Startup.ConfigureServices 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 metodu Newtonsoft.Json.JsonConvert.SerializeObject k serializaci JsonPatchDocument.

Metoda požadavku HTTP PATCH

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

Oprava JSON

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

Například následující dokumenty JSON představují prostředek, dokument opravy JSON pro prostředek a výsledek použití operací Patch.

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:

  • Vlastnost op označuje typ operace.
  • Vlastnost path označuje prvek, který se má aktualizovat.
  • Vlastnost value poskytuje novou hodnotu.

Prostředek po opravě

Tady 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é použitím dokumentu opravy JSON na prostředek jsou atomické. Pokud jakákoli operace v seznamu selže, nepoužije se žádná operace v seznamu.

Syntaxe cesty

Vlastnost cesty 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 pole addresses by byl na /addresses/0. Chcete-li add na konec pole, použijte místo čísla /addresses/-indexu spojovník (-) .

Operace

Následující tabulka uvádí podporované operace definované ve specifikaci opravy JSON:

Operace Notes
add Přidejte vlastnost nebo prvek pole. Pro existující vlastnost: nastavte hodnotu.
remove Odeberte vlastnost nebo prvek pole.
replace Stejné jako remove následované add na stejném místě.
move Stejné jako remove ze zdroje, za nímž následuje add cíl s použitím hodnoty ze zdroje.
copy Stejné jako add cíl s použitím hodnoty ze zdroje.
test Vrátí stavový kód úspěchu, pokud hodnota at path = poskytnuta value.

Oprava JSON v ASP.NET Core

Základní implementace opravy JSON ASP.NET je k dispozici v balíčku NuGet Microsoft.AspNetCore.JsonPatch .

Kód metody akce

V kontroleru rozhraní API metoda akce pro opravu JSON:

  • Je opatřen poznámkami atributem HttpPatch .
  • Přijímá , JsonPatchDocument<T>obvykle s [FromBody].
  • Zavolá ApplyTo dokument opravy, aby změny použil.

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:

using System.Collections.Generic;

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

Ukázková metoda akce:

  • Vytvoří .Customer
  • Použije opravu.
  • Vrátí výsledek v textu odpovědi.

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

Stav modelu

Předchozí příklad metody akce volá přetížení ApplyTo , které přebírá stav modelu jako jeden z jeho parametrů. Pomocí této možnosti můžete v odpovědích zobrazit chybové zprávy. Následující příklad ukazuje text odpovědi 400 Chybný požadavek 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í

  • Pokud path odkazuje na prvek pole: vloží nový prvek před prvek určený 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ým objektem: přidá vlastnost.
    • Pokud je prostředek, který se má opravit, statický objekt: požadavek selže.

Následující ukázkový dokument opravy nastaví 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 odebrání

  • Pokud path odkazuje na prvek pole: odebere prvek.
  • Pokud path odkazuje na vlastnost:
    • Pokud je prostředek k opravě dynamickým objektem: odebere vlastnost.
    • Pokud je prostředek k opravě statický objekt:
      • Pokud je vlastnost nullable: nastaví ji na hodnotu null.
      • Pokud vlastnost není nullable, nastaví ji na default<T>.

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

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

Operace nahrazení

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

Následující ukázkový dokument opravy nastaví hodnotu CustomerName a nahradí 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 prvek pole: zkopíruje from element do umístění elementu path , pak spustí remove operaci prvku from .
  • Pokud path odkazuje na vlastnost: zkopíruje hodnotu from vlastnosti do path vlastnosti, pak spustí remove operaci vlastnosti from .
  • Pokud path odkazuje na neexistující vlastnost:
    • Pokud je prostředek, který se má opravit, statický objekt: požadavek selže.
    • Pokud prostředek k opravě je dynamický objekt: zkopíruje from vlastnost do umístění označeného path, pak spustí remove operaci s 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řejde Orders[1] 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 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"
  }
]

Testovací operace

Pokud se hodnota v umístění označeném path hodnotou liší od hodnoty 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 proběhly úspěšně.

Operace test se běžně používá k zabránění aktualizaci, když dojde ke konfliktu 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í vzorového kódu (postup stahování).

Ukázku otestujete spuštěním aplikace a odesláním požadavků HTTP s následujícím nastavením:

  • 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ší materiály