Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln beskriver hur du hanterar JSON-korrigeringsbegäranden i ett ASP.NET Core-webb-API.
JSON Patch-stöd i ASP.NET Core-webb-API:et baseras på System.Text.Json serialisering och kräver Microsoft.AspNetCore.JsonPatch.SystemTextJson NuGet-paketet.
Vad är JSON Patch-standarden?
JSON-korrigeringsstandarden:
Är ett standardformat för att beskriva ändringar som ska tillämpas på ett JSON-dokument.
Definieras i RFC 6902 och används ofta i RESTful-API:er för att utföra partiella uppdateringar av JSON-resurser.
Beskriver en sekvens med åtgärder som ändrar ett JSON-dokument, till exempel:
addremovereplacemovecopytest
I webbappar används JSON Patch ofta i en PATCH-åtgärd för att utföra partiella uppdateringar av en resurs. I stället för att skicka hela resursen för en uppdatering kan klienter skicka ett JSON Patch-dokument som bara innehåller ändringarna. Patchning minskar extern databelastning och förbättrar effektiviteten.
En översikt över JSON Patch-standarden finns i jsonpatch.com.
JSON-korrigeringsstöd i ASP.NET Core-webb-API
JSON Patch-stöd i ASP.NET Core-webb-API baseras på System.Text.Json serialisering, med start i .NET 10 där man implementerar Microsoft.AspNetCore.JsonPatch baserat på System.Text.Json serialisering. Den här funktionen:
- Kräver NuGet-paketet
Microsoft.AspNetCore.JsonPatch.SystemTextJson. - Överensstämmer med moderna .NET-metoder genom att System.Text.Json använda biblioteket, som är optimerat för .NET.
- Ger bättre prestanda och minskad minnesanvändning jämfört med den äldre
Newtonsoft.Jsonimplementeringen. Mer information om den äldreNewtonsoft.Jsonimplementeringen finns i .NET 9-versionen av den här artikeln.
Note
Implementeringen av Microsoft.AspNetCore.JsonPatch baserad på System.Text.Json serialisering är inte en drop-in ersättning för den äldre Newtonsoft.Json-baserade implementeringen. Den stöder inte dynamiska typer, till exempel ExpandoObject.
Important
JSON Patch-standarden har inneboende säkerhetsrisker. Eftersom dessa risker är en del av JSON-korrigeringsstandarden försöker ASP.NET Core-implementeringen inte minimera inneboende säkerhetsrisker. Det är utvecklarens ansvar att se till att JSON Patch-dokumentet är säkert att tillämpa på målobjektet. Mer information finns i avsnittet Minimera säkerhetsrisker .
Aktivera JSON Patch-stöd med System.Text.Json
Om du vill aktivera JSON Patch-stöd med System.Text.Jsoninstallerar du Microsoft.AspNetCore.JsonPatch.SystemTextJson NuGet-paketet.
dotnet add package Microsoft.AspNetCore.JsonPatch.SystemTextJson --prerelease
Det här paketet innehåller en JsonPatchDocument<TModel> klass som representerar ett JSON Patch-dokument för objekt av typen T och anpassad logik för serialisering och deserialisering av JSON Patch-dokument med .System.Text.Json Nyckelmetoden för JsonPatchDocument<TModel> klassen är ApplyTo(Object), som tillämpar korrigeringsåtgärderna på ett målobjekt av typen T.
Åtgärdsmetodkod som tillämpar JSON-korrigering
I en API-kontrollant är en åtgärdsmetod för JSON Patch:
- Kommenteras med attributet HttpPatchAttribute .
- Accepterar en JsonPatchDocument<TModel>, vanligtvis med FromBodyAttribute.
- Anropar ändringsdokumentet ApplyTo(Object) för att tillämpa ändringarna.
Exempel på kontrollantåtgärdsmetod:
[HttpPatch("{id}", Name = "UpdateCustomer")]
public IActionResult Update(AppDb db, string id, [FromBody] JsonPatchDocument<Customer> patchDoc)
{
// Retrieve the customer by ID
var customer = db.Customers.FirstOrDefault(c => c.Id == id);
// Return 404 Not Found if customer doesn't exist
if (customer == null)
{
return NotFound();
}
patchDoc.ApplyTo(customer, jsonPatchError =>
{
var key = jsonPatchError.AffectedObject.GetType().Name;
ModelState.AddModelError(key, jsonPatchError.ErrorMessage);
}
);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return new ObjectResult(customer);
}
Den här koden från exempelappen fungerar med följande Customer och Order modeller:
namespace App.Models;
public class Customer
{
public string Id { get; set; }
public string? Name { get; set; }
public string? Email { get; set; }
public string? PhoneNumber { get; set; }
public string? Address { get; set; }
public List<Order>? Orders { get; set; }
public Customer()
{
Id = Guid.NewGuid().ToString();
}
}
namespace App.Models;
public class Order
{
public string Id { get; set; }
public DateTime? OrderDate { get; set; }
public DateTime? ShipDate { get; set; }
public decimal TotalAmount { get; set; }
public Order()
{
Id = Guid.NewGuid().ToString();
}
}
Exempelåtgärdsmetodens nyckelsteg:
-
Hämta kunden:
- Metoden hämtar ett
Customerobjekt från databasenAppDbmed hjälp av det angivna ID:t. - Om inget
Customerobjekt hittas returneras ett404 Not Foundsvar.
- Metoden hämtar ett
-
Tillämpa JSON-korrigering:
- Metoden ApplyTo(Object) tillämpar JSON Patch-åtgärderna från patchDoc på det hämtade
Customerobjektet. - Om fel uppstår under korrigeringsprogrammet, till exempel ogiltiga åtgärder eller konflikter, fångas de upp av ett ombud för felhantering. Denna delegat lägger till felmeddelanden till
ModelStatemed hjälp av typnamnet för det berörda objektet och felmeddelandet.
- Metoden ApplyTo(Object) tillämpar JSON Patch-åtgärderna från patchDoc på det hämtade
-
Verifiera ModelState:
- När korrigeringen har tillämpats söker metoden efter
ModelStatefel. - Om är
ModelStateogiltigt, till exempel på grund av korrigeringsfel, returneras ett400 Bad Requestsvar med valideringsfelen.
- När korrigeringen har tillämpats söker metoden efter
-
Returnera den uppdaterade kunden:
- Om korrigeringen har tillämpats och
ModelStateär giltig returnerar metoden det uppdateradeCustomerobjektet i svaret.
- Om korrigeringen har tillämpats och
Exempel på felsvar:
I följande exempel visas brödtexten för ett 400 Bad Request svar för en JSON-korrigeringsåtgärd när den angivna sökvägen är ogiltig:
{
"Customer": [
"The target location specified by path segment 'foobar' was not found."
]
}
Tillämpa ett JSON-korrigeringsdokument på ett objekt
Följande exempel visar hur du använder ApplyTo(Object) metoden för att tillämpa ett JSON-korrigeringsdokument på ett objekt.
Exempel: Tillämpa en JsonPatchDocument<TModel> på ett objekt
Följande exempel visar:
- Operationerna
add,replace, ochremove. - Åtgärder för kapslade egenskaper.
- Lägga till ett nytt objekt i en matris.
- Använda en JSON String Enum Converter i ett JSON-korrigeringsdokument.
// Original object
var person = new Person {
FirstName = "John",
LastName = "Doe",
Email = "johndoe@gmail.com",
PhoneNumbers = [new() {Number = "123-456-7890", Type = PhoneNumberType.Mobile}],
Address = new Address
{
Street = "123 Main St",
City = "Anytown",
State = "TX"
}
};
// Raw JSON patch document
string jsonPatch = """
[
{ "op": "replace", "path": "/FirstName", "value": "Jane" },
{ "op": "remove", "path": "/Email"},
{ "op": "add", "path": "/Address/ZipCode", "value": "90210" },
{ "op": "add", "path": "/PhoneNumbers/-", "value": { "Number": "987-654-3210",
"Type": "Work" } }
]
""";
// Deserialize the JSON patch document
var patchDoc = JsonSerializer.Deserialize<JsonPatchDocument<Person>>(jsonPatch);
// Apply the JSON patch document
patchDoc!.ApplyTo(person);
// Output updated object
Console.WriteLine(JsonSerializer.Serialize(person, serializerOptions));
Föregående exempel resulterar i följande utdata från det uppdaterade objektet:
{
"firstName": "Jane",
"lastName": "Doe",
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "TX",
"zipCode": "90210"
},
"phoneNumbers": [
{
"number": "123-456-7890",
"type": "Mobile"
},
{
"number": "987-654-3210",
"type": "Work"
}
]
}
Metoden ApplyTo(Object) följer vanligtvis konventionerna och alternativen för System.Text.Json vid bearbetning av JsonPatchDocument<TModel>, inklusive det beteende som styrs av följande alternativ:
- JsonNumberHandling: Om numeriska egenskaper går att läsa från strängar.
- PropertyNameCaseInsensitive: Om egenskapsnamn är skiftlägeskänsliga.
Viktiga skillnader mellan System.Text.Json och den nya JsonPatchDocument<TModel> implementeringen:
- Körningstypen för målobjektet, inte den deklarerade typen, avgör vilka egenskaper ApplyTo(Object) korrigerar.
- System.Text.Json deserialisering förlitar sig på den deklarerade typen för att identifiera relevanta egenskaper.
Exempel: Tillämpa en JsonPatchDocument med felhantering
Det finns olika fel som kan uppstå vid tillämpning av ett JSON-korrigeringsdokument. Målobjektet kanske till exempel inte har den angivna egenskapen, eller så kan det angivna värdet vara inkompatibelt med egenskapstypen.
JSON Patch stöder åtgärden test , som kontrollerar om ett angivet värde är lika med målegenskapen. Om den inte gör det returneras ett fel.
I följande exempel visas hur du hanterar dessa fel på ett korrekt sätt.
Important
Det objekt som skickas till ApplyTo(Object)-metoden ändras direkt. Anroparen ansvarar för att ignorera ändringar om någon åtgärd misslyckas.
// Original object
var person = new Person {
FirstName = "John",
LastName = "Doe",
Email = "johndoe@gmail.com"
};
// Raw JSON patch document
string jsonPatch = """
[
{ "op": "replace", "path": "/Email", "value": "janedoe@gmail.com"},
{ "op": "test", "path": "/FirstName", "value": "Jane" },
{ "op": "replace", "path": "/LastName", "value": "Smith" }
]
""";
// Deserialize the JSON patch document
var patchDoc = JsonSerializer.Deserialize<JsonPatchDocument<Person>>(jsonPatch);
// Apply the JSON patch document, catching any errors
Dictionary<string, string[]>? errors = null;
patchDoc!.ApplyTo(person, jsonPatchError =>
{
errors ??= new ();
var key = jsonPatchError.AffectedObject.GetType().Name;
if (!errors.ContainsKey(key))
{
errors.Add(key, new string[] { });
}
errors[key] = errors[key].Append(jsonPatchError.ErrorMessage).ToArray();
});
if (errors != null)
{
// Print the errors
foreach (var error in errors)
{
Console.WriteLine($"Error in {error.Key}: {string.Join(", ", error.Value)}");
}
}
// Output updated object
Console.WriteLine(JsonSerializer.Serialize(person, serializerOptions));
Föregående exempel resulterar i följande utdata:
Error in Person: The current value 'John' at path 'FirstName' is not equal
to the test value 'Jane'.
{
"firstName": "John",
"lastName": "Smith", <<< Modified!
"email": "janedoe@gmail.com", <<< Modified!
"phoneNumbers": []
}
Minimera säkerhetsrisker
När du Microsoft.AspNetCore.JsonPatch.SystemTextJson använder paketet är det viktigt att förstå och minimera potentiella säkerhetsrisker. I följande avsnitt beskrivs de identifierade säkerhetsrisker som är associerade med JSON Patch och ger rekommenderade åtgärder för att säkerställa säker användning av paketet.
Important
Detta är inte en fullständig lista över hot. Apputvecklare måste utföra sina egna hotmodellgranskningar för att fastställa en appspecifik omfattande lista och komma med lämpliga åtgärder efter behov. Till exempel bör appar som exponerar samlingar för korrigeringsåtgärder ta hänsyn till risken för algoritmiska komplexitetsattacker om dessa åtgärder infogar eller tar bort element i början av samlingen.
För att minimera säkerhetsriskerna när de integrerar JSON Patch-funktioner i sina appar bör utvecklare:
- Kör omfattande hotmodeller för sina egna appar.
- Åtgärda identifierade hot.
- Följ de rekommenderade åtgärderna i följande avsnitt.
DoS (Denial of Service) via minnesförstärkning
-
Scenario: En skadlig klient skickar en
copyåtgärd som duplicerar stora objektdiagram flera gånger, vilket leder till överdriven minnesförbrukning. - Effekt: Potentiella OOM-villkor (Out-Of-Memory) som orsakar avbrott i tjänsten.
-
Mitigation:
- Verifiera inkommande JSON-korrigeringsdokument för storlek och struktur innan du anropar ApplyTo(Object).
- Valideringen måste vara appspecifik, men ett exempelvalidering kan se ut ungefär så här:
public void Validate(JsonPatchDocument<T> patch)
{
// This is just an example. It's up to the developer to make sure that
// this case is handled properly, based on the app needs.
if (patch.Operations.Where(op=>op.OperationType == OperationType.Copy).Count()
> MaxCopyOperationsCount)
{
throw new InvalidOperationException();
}
}
Underminering av affärslogik
- Scenario: Korrigeringsåtgärder kan ändra fält med implicita invarianter (till exempel interna flaggor, ID:er eller beräknade fält), vilket bryter mot affärsbegränsningar.
- Effekt: Problem med dataintegritet och oavsiktligt appbeteende.
-
Mitigation:
- Använd POCOs (Vanliga gamla CLR-objekt) med explicit definierade egenskaper som är säkra att ändra.
- Undvik att exponera känsliga eller säkerhetskritiska egenskaper i målobjektet.
- Om ett POCO-objekt inte används verifierar du det korrigerade objektet efter att åtgärder har tillämpats för att säkerställa att affärsregler och invarianter inte överträds.
- Använd POCOs (Vanliga gamla CLR-objekt) med explicit definierade egenskaper som är säkra att ändra.
Autentisering och auktorisering
- Scenario: Oautentiserade eller obehöriga klienter skickar skadliga JSON-korrigeringsbegäranden.
- Effekt: Obehörig åtkomst för att ändra känsliga data eller störa appens beteende.
-
Mitigation:
- Skydda slutpunkter som accepterar JSON-korrigeringsbegäranden med rätt autentiserings- och auktoriseringsmekanismer.
- Begränsa åtkomsten till betrodda klienter eller användare med lämpliga behörigheter.
Hämta koden
Visa eller ladda ned exempelkod. (Ladda ned).
Testa exemplet genom att köra appen och skicka HTTP-begäranden med följande inställningar:
- URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - HTTP-metod:
PATCH - Rubrik:
Content-Type: application/json-patch+json - Brödtext: Kopiera och klistra in ett av JSON-korrigeringsdokumentexemplen från JSON-projektmappen .
Ytterligare resurser
Den här artikeln beskriver hur du hanterar JSON-korrigeringsbegäranden i ett ASP.NET Core-webb-API.
Important
JSON Patch-standarden har inneboende säkerhetsrisker. Den här implementeringen försöker inte minimera dessa inneboende säkerhetsrisker. Det är utvecklarens ansvar att se till att JSON Patch-dokumentet är säkert att tillämpa på målobjektet. Mer information finns i avsnittet Minimera säkerhetsrisker .
Paketinstallation
JSON Patch-stöd i ASP.NET Core-webb-API baseras på Newtonsoft.Json och kräver Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet-paketet.
Så här aktiverar du stöd för JSON-korrigering:
Installera NuGet-paketet
Microsoft.AspNetCore.Mvc.NewtonsoftJson.Ringa AddNewtonsoftJson. Till exempel:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddNewtonsoftJson(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
AddNewtonsoftJson ersätter de standardbaserade System.Text.Jsonin- och utdataformatrarna som används för att formatera allt JSON-innehåll. Den här tilläggsmetoden är kompatibel med följande MVC-tjänstregistreringsmetoder:
JsonPatch kräver att huvud sätts till Content-Typeapplication/json-patch+json.
Lägg till stöd för JSON-korrigering när du använder System.Text.Json
Den System.Text.Json-baserade indataformaterare stöder inte JSON Patch. Så här lägger du till stöd för JSON Patch med , Newtonsoft.Jsonsamtidigt som de andra in- och utdataformatrarna lämnas oförändrade:
Installera NuGet-paketet
Microsoft.AspNetCore.Mvc.NewtonsoftJson.Uppdatera
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(); } }
Föregående kod skapar en instans av NewtonsoftJsonPatchInputFormatter och infogar den som den första posten i MvcOptions.InputFormatters samlingen. Den här registreringsordningen säkerställer att:
-
NewtonsoftJsonPatchInputFormatterbearbetar JSON Patch-begäranden. - De befintliga
System.Text.Json-baserade indata- och formatrarna bearbetar alla andra JSON-begäranden och -svar.
Använd Newtonsoft.Json.JsonConvert.SerializeObject-metoden för att serialisera en JsonPatchDocument.
PATCH HTTP-begärandemetod
METODERNA PUT och PATCH används för att uppdatera en befintlig resurs. Skillnaden mellan dem är att PUT ersätter hela resursen, medan PATCH endast anger ändringarna.
JSON-korrigering
JSON Patch är ett format för att ange uppdateringar som ska tillämpas på en resurs. Ett JSON Patch-dokument har en matris med åtgärder. Varje åtgärd identifierar en viss typ av ändring. Exempel på sådana ändringar är att lägga till ett matriselement eller ersätta ett egenskapsvärde.
Följande JSON-dokument representerar till exempel en resurs, ett JSON Patch-dokument för resursen och resultatet av att tillämpa korrigeringsåtgärderna.
Resursexempel
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
JSON-patchexempel
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
I JSON-koden ovan:
- Egenskapen
opanger typen av åtgärd. - Egenskapen
pathanger det element som ska uppdateras. - Egenskapen
valueinnehåller det nya värdet.
Resurs efter korrigering
Här är resursen efter att du har tillämpat föregående JSON-korrigeringsdokument:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Ändringarna som görs genom att tillämpa ett JSON-korrigeringsdokument på en resurs är atomiska. Om någon åtgärd i listan misslyckas tillämpas ingen åtgärd i listan.
Sökvägssyntax
Sökvägsegenskapen för ett åtgärdsobjekt har snedstreck mellan nivåer. Till exempel "/address/zipCode".
Nollbaserade index används för att ange matriselement. Det första elementet i matrisen addresses skulle vara på /addresses/0. Till add slutet av en matris använder du ett bindestreck (-) i stället för ett indexnummer: /addresses/-.
Operations
I följande tabell visas åtgärder som stöds enligt definitionen i JSON Patch-specifikationen:
| Operation | Notes |
|---|---|
add |
Lägg till en egenskap eller ett matriselement. För befintlig egenskap: ange värde. |
remove |
Ta bort en egenskap eller ett matriselement. |
replace |
Samma som remove följt av add på samma plats. |
move |
Samma som remove från källa följt av add till destination använder värdet från källan. |
copy |
Samma som add till destinationen med värdet från källan. |
test |
Returnera en statuskod för lyckad om värdet vid path är satt till angivet value. |
JSON-korrigering i ASP.NET Core
ASP.NET Core-implementeringen av JSON Patch finns i NuGet-paketet Microsoft.AspNetCore.JsonPatch .
Åtgärdsmetodkod
I en API-kontrollant är en åtgärdsmetod för JSON Patch:
- Kommenteras med attributet
HttpPatch. - Accepterar en JsonPatchDocument<TModel>, vanligtvis med
[FromBody]. - Anropar ändringsdokumentet ApplyTo(Object) för att tillämpa ändringarna.
Här är ett exempel:
[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);
}
}
Den här koden från exempelappen fungerar med följande Customer modell:
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; }
}
Exempelåtgärdsmetoden:
- Konstruerar en
Customer. - Tillämpar patchen.
- Returnerar resultatet i svarets brödtext.
I en riktig app hämtar koden data från ett arkiv, till exempel en databas, och uppdaterar databasen efter att korrigeringen har tillämpats.
Modelltillstånd
Föregående exempel på åtgärdsmetod anropar en överbelastning av ApplyTo som tar modelltillstånd som en av sina parametrar. Med det här alternativet kan du få felmeddelanden i svar. I följande exempel visas huvuddelen av ett 400 Dålig begäran-svar för en test åtgärd:
{
"Customer": [
"The current value 'John' at path 'customerName' != test value 'Nancy'."
]
}
Dynamiska objekt
Följande åtgärdsmetodexempel visar hur du tillämpar en korrigering på ett dynamiskt objekt:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Lägg till-åtgärden
- Om
pathpekar på ett matriselement: infogar nytt element innan det som anges avpath. - Om
pathpekar på en egenskap: anger egenskapsvärdet. - Om
pathpekar på en obefintlig plats:- Om resursen som ska korrigeras är ett dynamiskt objekt: lägger till en egenskap.
- Om resursen som ska korrigeras är ett statiskt objekt: begäran misslyckas.
Följande exempelkorrigeringsdokument anger värdet CustomerName för och lägger till ett Order objekt i slutet av matrisen Orders .
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Borttagningsåtgärden
- Om
pathpekar på ett matriselement: tar bort elementet. - Om
pathpekar på en egenskap:- Om resursen som ska korrigeras är ett dynamiskt objekt: tar bort egenskapen.
- Om resursen som ska korrigeras är ett statiskt objekt:
- Om egenskapen är nullbar: anger den till null.
- Om egenskapen inte är nullbar anger du den till
default<T>.
Följande exempelkorrigeringsdokument anger CustomerName null och tar bort Orders[0]:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Ersättningsåtgärden
Den här åtgärden fungerar på samma sätt som en remove följt av en add.
Följande exempelkorrigeringsdokument anger värdet CustomerName för och ersätter Orders[0]med ett nytt Order objekt:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Flyttåtgärden
- Om
pathpekar på ett matriselement: kopierasfromelementet till platsen förpathelementet, och sedan körs enremoveåtgärd påfromelementet. - Om
pathpekar på en egenskap: kopieras värdet förfromegenskapen tillpathegenskapen, och sedan körs enremoveåtgärd påfromegenskapen. - Om
pathpekar på en icke-existerande egenskap:- Om resursen som ska korrigeras är ett statiskt objekt: begäran misslyckas.
- Om resursen som ska korrigeras är ett dynamiskt objekt: kopierar
fromegenskapen till den plats som anges avpathoch kör sedan enremoveåtgärd påfromegenskapen.
Följande exempelkorrigeringsdokument:
- Kopierar värdet av
Orders[0].OrderNametillCustomerName. - Ställer in
Orders[0].OrderNametill nullvärde. - Flytta
Orders[1]till föreOrders[0].
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Kopieringsåtgärden
Den här åtgärden fungerar på samma sätt som en move åtgärd utan det sista remove steget.
Följande exempelkorrigeringsdokument:
- Kopierar värdet av
Orders[0].OrderNametillCustomerName. - Infogar en kopia av
Orders[1]föreOrders[0].
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Teståtgärden
Om värdet på den plats som anges av path skiljer sig från det värde som anges i valuemisslyckas begäran. I så fall misslyckas hela PATCH-begäran även om alla andra åtgärder i korrigeringsdokumentet annars skulle lyckas.
Åtgärden test används ofta för att förhindra en uppdatering när det finns en samtidighetskonflikt.
Följande exempelkorrigeringsdokument har ingen effekt om det ursprungliga värdet CustomerName för är "John", eftersom testet misslyckas:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Hämta koden
Visa eller ladda ned exempelkod. (Ladda ned).
Testa exemplet genom att köra appen och skicka HTTP-begäranden med följande inställningar:
- URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - HTTP-metod:
PATCH - Rubrik:
Content-Type: application/json-patch+json - Brödtext: Kopiera och klistra in ett av JSON-korrigeringsdokumentexemplen från JSON-projektmappen .
Minimera säkerhetsrisker
När du använder Microsoft.AspNetCore.JsonPatch paketet med den Newtonsoft.Json-baserade implementeringen är det viktigt att förstå och minimera potentiella säkerhetsrisker. I följande avsnitt beskrivs de identifierade säkerhetsrisker som är associerade med JSON Patch och ger rekommenderade åtgärder för att säkerställa säker användning av paketet.
Important
Detta är inte en fullständig lista över hot. Apputvecklare måste utföra sina egna hotmodellgranskningar för att fastställa en appspecifik omfattande lista och komma med lämpliga åtgärder efter behov. Till exempel bör appar som exponerar samlingar för korrigeringsåtgärder ta hänsyn till risken för algoritmiska komplexitetsattacker om dessa åtgärder infogar eller tar bort element i början av samlingen.
Genom att köra omfattande hotmodeller för sina egna appar och hantera identifierade hot samtidigt som de följer de rekommenderade åtgärderna nedan kan konsumenter av dessa paket integrera JSON Patch-funktioner i sina appar samtidigt som säkerhetsriskerna minimeras.
DoS (Denial of Service) via minnesförstärkning
-
Scenario: En skadlig klient skickar en
copyåtgärd som duplicerar stora objektdiagram flera gånger, vilket leder till överdriven minnesförbrukning. - Effekt: Potentiella OOM-villkor (Out-Of-Memory) som orsakar avbrott i tjänsten.
-
Mitigation:
- Verifiera inkommande JSON-korrigeringsdokument för storlek och struktur innan du anropar
ApplyTo. - Valideringen måste vara appspecifik, men ett exempelvalidering kan se ut ungefär så här:
- Verifiera inkommande JSON-korrigeringsdokument för storlek och struktur innan du anropar
public void Validate(JsonPatchDocument patch)
{
// This is just an example. It's up to the developer to make sure that
// this case is handled properly, based on the app needs.
if (patch.Operations.Where(op => op.OperationType == OperationType.Copy).Count()
> MaxCopyOperationsCount)
{
throw new InvalidOperationException();
}
}
Underminering av affärslogik
- Scenario: Korrigeringsåtgärder kan ändra fält med implicita invarianter (till exempel interna flaggor, ID:er eller beräknade fält), vilket bryter mot affärsbegränsningar.
- Effekt: Problem med dataintegritet och oavsiktligt appbeteende.
-
Mitigation:
- Använd POCO-objekt med explicit definierade egenskaper som är säkra att ändra.
- Undvik att exponera känsliga eller säkerhetskritiska egenskaper i målobjektet.
- Om inget POCO-objekt används verifierar du det korrigerade objektet efter att åtgärder har tillämpats för att säkerställa att affärsregler och invarianter inte överträds.
Autentisering och auktorisering
- Scenario: Oautentiserade eller obehöriga klienter skickar skadliga JSON-korrigeringsbegäranden.
- Effekt: Obehörig åtkomst för att ändra känsliga data eller störa appens beteende.
-
Mitigation:
- Skydda slutpunkter som accepterar JSON-korrigeringsbegäranden med rätt autentiserings- och auktoriseringsmekanismer.
- Begränsa åtkomsten till betrodda klienter eller användare med lämpliga behörigheter.
Ytterligare resurser
Den här artikeln beskriver hur du hanterar JSON-korrigeringsbegäranden i ett ASP.NET Core-webb-API.
Important
JSON Patch-standarden har inneboende säkerhetsrisker. Eftersom dessa risker är en del av JSON Patch-standarden försöker den här implementeringen inte minska de inneboende säkerhetsriskerna. Det är utvecklarens ansvar att se till att JSON Patch-dokumentet är säkert att tillämpa på målobjektet. Mer information finns i avsnittet Minimera säkerhetsrisker .
Paketinstallation
Utför följande steg för att aktivera JSON Patch-stöd i din app:
Installera NuGet-paketet
Microsoft.AspNetCore.Mvc.NewtonsoftJson.Uppdatera projektets
Startup.ConfigureServicesmetod för att anropa AddNewtonsoftJson. Till exempel:services .AddControllersWithViews() .AddNewtonsoftJson();
AddNewtonsoftJson är kompatibel med MVC-tjänstregistreringsmetoderna:
JSON Patch, AddNewtonsoftJson och System.Text.Json
AddNewtonsoftJson ersätter de System.Text.Json-baserade in- och utdataformaterare som används för att formatera allt JSON-innehåll. Om du vill lägga till stöd för JSON Patch med Newtonsoft.Json, samtidigt som de andra formatrarna lämnas oförändrade, uppdaterar du projektets Startup.ConfigureServices-metod enligt följande:
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();
}
Föregående kod kräver Microsoft.AspNetCore.Mvc.NewtonsoftJson paketet och följande using instruktioner:
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;
Newtonsoft.Json.JsonConvert.SerializeObject Använd metoden för att serialisera en JsonPatchDocument.
PATCH HTTP-begärandemetod
METODERNA PUT och PATCH används för att uppdatera en befintlig resurs. Skillnaden mellan dem är att PUT ersätter hela resursen, medan PATCH endast anger ändringarna.
JSON-korrigering
JSON Patch är ett format för att ange uppdateringar som ska tillämpas på en resurs. Ett JSON Patch-dokument har en matris med åtgärder. Varje åtgärd identifierar en viss typ av ändring. Exempel på sådana ändringar är att lägga till ett matriselement eller ersätta ett egenskapsvärde.
Följande JSON-dokument representerar till exempel en resurs, ett JSON Patch-dokument för resursen och resultatet av att tillämpa korrigeringsåtgärderna.
Resursexempel
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
JSON-patchexempel
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
I JSON-koden ovan:
- Egenskapen
opanger typen av åtgärd. - Egenskapen
pathanger det element som ska uppdateras. - Egenskapen
valueinnehåller det nya värdet.
Resurs efter korrigering
Här är resursen efter att du har tillämpat föregående JSON-korrigeringsdokument:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Ändringarna som görs genom att tillämpa ett JSON-korrigeringsdokument på en resurs är atomiska. Om någon åtgärd i listan misslyckas tillämpas ingen åtgärd i listan.
Sökvägssyntax
Sökvägsegenskapen för ett åtgärdsobjekt har snedstreck mellan nivåer. Till exempel "/address/zipCode".
Nollbaserade index används för att ange matriselement. Det första elementet i matrisen addresses skulle vara på /addresses/0. Till add slutet av en matris använder du ett bindestreck (-) i stället för ett indexnummer: /addresses/-.
Operations
I följande tabell visas åtgärder som stöds enligt definitionen i JSON Patch-specifikationen:
| Operation | Notes |
|---|---|
add |
Lägg till en egenskap eller ett matriselement. För befintlig egenskap: ange värde. |
remove |
Ta bort en egenskap eller ett matriselement. |
replace |
Samma som remove följt av add på samma plats. |
move |
Samma som remove från källa följt av add till destination använder värdet från källan. |
copy |
Samma som add till destinationen med värdet från källan. |
test |
Returnera en statuskod för lyckad om värdet vid path är satt till angivet value. |
JSON-korrigering i ASP.NET Core
ASP.NET Core-implementeringen av JSON Patch finns i NuGet-paketet Microsoft.AspNetCore.JsonPatch .
Åtgärdsmetodkod
I en API-kontrollant är en åtgärdsmetod för JSON Patch:
- Kommenteras med attributet
HttpPatch. - Accepterar en
JsonPatchDocument<T>, vanligtvis med[FromBody]. - Anropar ändringsdokumentet
ApplyToför att tillämpa ändringarna.
Här är ett exempel:
[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);
}
}
Den här koden från exempelappen fungerar med följande Customer modell:
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; }
}
}
Exempelåtgärdsmetoden:
- Konstruerar en
Customer. - Tillämpar patchen.
- Returnerar resultatet i svarets brödtext.
I en riktig app hämtar koden data från ett arkiv, till exempel en databas, och uppdaterar databasen efter att korrigeringen har tillämpats.
Modelltillstånd
Föregående exempel på åtgärdsmetod anropar en överbelastning av ApplyTo som tar modelltillstånd som en av sina parametrar. Med det här alternativet kan du få felmeddelanden i svar. I följande exempel visas huvuddelen av ett 400 Dålig begäran-svar för en test åtgärd:
{
"Customer": [
"The current value 'John' at path 'customerName' is not equal to the test value 'Nancy'."
]
}
Dynamiska objekt
Följande åtgärdsmetodexempel visar hur du tillämpar en korrigering på ett dynamiskt objekt:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Lägg till-åtgärden
- Om
pathpekar på ett matriselement: infogar nytt element innan det som anges avpath. - Om
pathpekar på en egenskap: anger egenskapsvärdet. - Om
pathpekar på en obefintlig plats:- Om resursen som ska korrigeras är ett dynamiskt objekt: lägger till en egenskap.
- Om resursen som ska korrigeras är ett statiskt objekt: begäran misslyckas.
Följande exempelkorrigeringsdokument anger värdet CustomerName för och lägger till ett Order objekt i slutet av matrisen Orders .
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Borttagningsåtgärden
- Om
pathpekar på ett matriselement: tar bort elementet. - Om
pathpekar på en egenskap:- Om resursen som ska korrigeras är ett dynamiskt objekt: tar bort egenskapen.
- Om resursen som ska korrigeras är ett statiskt objekt:
- Om egenskapen är nullbar: anger den till null.
- Om egenskapen inte är nullbar anger du den till
default<T>.
Följande exempelkorrigeringsdokument anger CustomerName null och tar bort Orders[0]:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Ersättningsåtgärden
Den här åtgärden fungerar på samma sätt som en remove följt av en add.
Följande exempelkorrigeringsdokument anger värdet CustomerName för och ersätter Orders[0]med ett nytt Order objekt:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Flyttåtgärden
- Om
pathpekar på ett matriselement: kopierasfromelementet till platsen förpathelementet, och sedan körs enremoveåtgärd påfromelementet. - Om
pathpekar på en egenskap: kopieras värdet förfromegenskapen tillpathegenskapen, och sedan körs enremoveåtgärd påfromegenskapen. - Om
pathpekar på en icke-existerande egenskap:- Om resursen som ska korrigeras är ett statiskt objekt: begäran misslyckas.
- Om resursen som ska korrigeras är ett dynamiskt objekt: kopierar
fromegenskapen till den plats som anges avpathoch kör sedan enremoveåtgärd påfromegenskapen.
Följande exempelkorrigeringsdokument:
- Kopierar värdet av
Orders[0].OrderNametillCustomerName. - Ställer in
Orders[0].OrderNametill nullvärde. - Flytta
Orders[1]till föreOrders[0].
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Kopieringsåtgärden
Den här åtgärden fungerar på samma sätt som en move åtgärd utan det sista remove steget.
Följande exempelkorrigeringsdokument:
- Kopierar värdet av
Orders[0].OrderNametillCustomerName. - Infogar en kopia av
Orders[1]föreOrders[0].
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Teståtgärden
Om värdet på den plats som anges av path skiljer sig från det värde som anges i valuemisslyckas begäran. I så fall misslyckas hela PATCH-begäran även om alla andra åtgärder i korrigeringsdokumentet annars skulle lyckas.
Åtgärden test används ofta för att förhindra en uppdatering när det finns en samtidighetskonflikt.
Följande exempelkorrigeringsdokument har ingen effekt om det ursprungliga värdet CustomerName för är "John", eftersom testet misslyckas:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Hämta koden
Visa eller ladda ned exempelkod. (Ladda ned).
Testa exemplet genom att köra appen och skicka HTTP-begäranden med följande inställningar:
- URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - HTTP-metod:
PATCH - Rubrik:
Content-Type: application/json-patch+json - Brödtext: Kopiera och klistra in ett av JSON-korrigeringsdokumentexemplen från JSON-projektmappen .
ASP.NET Core