Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a cikk bemutatja, hogyan kezelheti a JSON-javítás kéréseit egy ASP.NET Core webes API-ban.
A JSON Patch támogatása a ASP.NET Core webes API-ban szerializáláson System.Text.Json alapul, és a Microsoft.AspNetCore.JsonPatch.SystemTextJson NuGet-csomagot igényli.
Mi a JSON Patch szabvány?
A JSON-javítás szabványa:
A JSON-dokumentumokra alkalmazandó módosítások leírásának szabványos formátuma.
Az RFC 6902-ben van definiálva, és széles körben használják a RESTful API-kban a JSON-erőforrások részleges frissítéséhez.
A JSON-dokumentumokat módosító műveletek sorozatát ismerteti, például:
addremovereplacemovecopytest
A webalkalmazásokban a JSON-javítást gyakran használják a PATCH műveletben az erőforrás részleges frissítéséhez. Ahelyett, hogy a teljes erőforrást elküldené egy frissítéshez, az ügyfelek küldhetnek egy JSON Patch-dokumentumot, amely csak a módosításokat tartalmazza. A javítás csökkenti a hasznos adatok méretét és javítja a hatékonyságot.
A JSON-javítás szabványának áttekintéséhez tekintse meg a jsonpatch.com.
JSON-javítás támogatása a ASP.NET Core webes API-ban
A JSON Patch támogatása az ASP.NET Core webes API-ban a System.Text.Json szerializáláson alapul, és a .NET 10-től kezdve a Microsoft.AspNetCore.JsonPatch szerializáláson alapuló System.Text.Json implementálást valósítja meg. Ez a funkció:
- A NuGet-csomag
Microsoft.AspNetCore.JsonPatch.SystemTextJsonszükséges. - A .NET-hez optimalizált kódtár használatával igazodik a System.Text.Json modern .NET-eljárásokhoz.
- Jobb teljesítményt és kevesebb memóriahasználatot biztosít az örökölt
Newtonsoft.Jsonimplementációhoz képest. Az örököltNewtonsoft.Jsonimplementációval kapcsolatos további információkért tekintse meg a cikk .NET 9-es verzióját.
Note
A Microsoft.AspNetCore.JsonPatch-alapú szerializáción alapuló System.Text.Json implementáció nem helyettesíti a régi Newtonsoft.Json-alapú implementációt. Nem támogatja például ExpandoObjecta dinamikus típusokat.
Important
A JSON Patch szabvány belső biztonsági kockázatokkal jár. Mivel ezek a kockázatok a JSON Patch szabványhoz tartoznak, a ASP.NET Core-implementáció nem próbálja csökkenteni az eredendő biztonsági kockázatokat. A fejlesztő felelőssége annak biztosítása, hogy a JSON Patch-dokumentum biztonságosan alkalmazható legyen a célobjektumra. További információ: A biztonsági kockázatok mérséklése szakasz.
A JSON-javítás támogatásának engedélyezése System.Text.Json
A JSON-javítás támogatásának System.Text.Jsonengedélyezéséhez telepítse a Microsoft.AspNetCore.JsonPatch.SystemTextJson NuGet-csomagot.
dotnet add package Microsoft.AspNetCore.JsonPatch.SystemTextJson --prerelease
Ez a csomag egy JsonPatchDocument<TModel> osztályt biztosít a JSON Patch dokumentumok T típusú objektumokhoz való reprezentálásához, valamint egyedi logikát a JSON Patch dokumentumok System.Text.Json szerializálásához és deszerializálásához. A JsonPatchDocument<TModel> osztály kulcsmetódusa a ApplyTo(Object), amely a javításműveleteket egy T típusú célobjektumra alkalmazza.
A JSON-javítást alkalmazó műveletmetódus kódja
Egy API-vezérlőben a JSON-javítás műveletmetódusa:
- A(z) HttpPatchAttribute attribútummal van megjelölve.
- Elfogad egy JsonPatchDocument<TModel>, általában a FromBodyAttribute.
- A módosítások alkalmazásához ApplyTo(Object) hívja meg a módosítási dokumentumot.
Példa vezérlőműveleti módszerre:
[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);
}
A mintaalkalmazásból származó kód a következőkkel Customer és Order modellekkel működik:
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();
}
}
A mintaműveleti módszer fő lépései:
-
Kérje le az ügyfelet:
- A metódus egy
Customerobjektumot kér le az adatbázisbólAppDba megadott azonosító használatával. - Ha nem található
Customerobjektum,404 Not Foundválaszt ad.
- A metódus egy
-
JSON-javítás alkalmazása:
- A ApplyTo(Object) metódus a patchDoc JSON Patch-műveleteit alkalmazza a lekért
Customerobjektumra. - Ha a javításalkalmazás során hibák lépnek fel, például érvénytelen műveletek vagy ütközések, a hibakezelő meghatalmazott rögzíti őket. Ez a meghatalmazott hibaüzeneteket ad hozzá az
ModelStateérintett objektum típusnevének és a hibaüzenetnek a használatával.
- A ApplyTo(Object) metódus a patchDoc JSON Patch-műveleteit alkalmazza a lekért
-
ModelState ellenőrzése:
- A javítás alkalmazása után a metódus ellenőrzi a
ModelStatehibákat. - Ha a
ModelStateérvénytelen, például javítási hibák miatt, akkor400 Bad Requestválaszt ad vissza az érvényesítési hibákkal.
- A javítás alkalmazása után a metódus ellenőrzi a
-
Visszatéríti a frissített ügyfelet:
- Ha a javítás sikeresen alkalmazva van, és az
ModelStateérvényes, a metódus visszaadja a frissítettCustomerobjektumot a válaszban.
- Ha a javítás sikeresen alkalmazva van, és az
Példa hibaválasz:
Az alábbi példa egy JSON-javításművelet válaszának törzsét 400 Bad Request mutatja be, ha a megadott elérési út érvénytelen:
{
"Customer": [
"The target location specified by path segment 'foobar' was not found."
]
}
JSON Patch-dokumentum alkalmazása objektumra
Az alábbi példák bemutatják, hogyan alkalmazhat JSON Patch-dokumentumot egy objektumra a ApplyTo(Object) metódus használatával.
Példa: Alkalmazzon egy JsonPatchDocument<TModel> egy objektumra
Az alábbi példa a következőket mutatja be:
- A
add,replaceésremoveműveletek. - Műveletek beágyazott tulajdonságokon.
- Új elem hozzáadása tömbhöz.
- JSON-sztring Enum-konverter használata egy JSON módosító dokumentumban.
// 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));
Az előző példa a frissített objektum következő kimenetét eredményezi:
{
"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"
}
]
}
A ApplyTo(Object) módszer általában a System.Text.Json konvencióit és lehetőségeit követi az JsonPatchDocument<TModel> feldolgozásához, beleértve a következő beállítások által szabályozott viselkedést is:
- JsonNumberHandling: Azt jelzi, hogy a numerikus tulajdonságok sztringekből vannak-e beolvasva.
- PropertyNameCaseInsensitive: A tulajdonságnevek megkülönböztetik-e a kis- és nagybetűket.
Főbb különbségek a System.Text.Json és az új JsonPatchDocument<TModel> implementáció között:
- A célobjektum futásidejű típusa, nem a deklarált típus határozza meg, hogy mely tulajdonságokra vonatkoznak a ApplyTo(Object) módosítások.
- System.Text.Json A deszerializálás a deklarált típusra támaszkodik a jogosult tulajdonságok azonosításához.
Példa: JsonPatchDocument alkalmazása hibakezeléssel
A JSON-javítás dokumentumainak alkalmazásakor különböző hibák léphetnek fel. Előfordulhat például, hogy a célobjektum nem rendelkezik a megadott tulajdonsággal, vagy a megadott érték nem kompatibilis a tulajdonságtípussal.
A JSON Patch támogatja a test műveletet, amely ellenőrzi, hogy egy megadott érték megegyezik-e a céltulajdonságokkal. Ha nem, hibát ad vissza.
Az alábbi példa bemutatja, hogyan kezelheti ezeket a hibákat elegánsan.
Important
A metódusnak ApplyTo(Object) átadott objektum a helyén módosul. Ha egy művelet meghiúsul, a hívó felelős a módosítások elvetéséért.
// 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));
Az előző példa a következő kimenetet eredményezi:
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": []
}
A biztonsági kockázatok mérséklése
A csomag használatakor Microsoft.AspNetCore.JsonPatch.SystemTextJson kritikus fontosságú a lehetséges biztonsági kockázatok megértése és csökkentése. A következő szakaszok ismertetik a JSON-javításhoz kapcsolódó azonosított biztonsági kockázatokat, és ajánlott megoldásokat nyújtanak a csomag biztonságos használatának biztosítása érdekében.
Important
Ez nem a fenyegetések teljes listája. Az alkalmazásfejlesztőknek saját fenyegetésmodell-felülvizsgálatokat kell végezniük az alkalmazásspecifikus átfogó lista meghatározásához, és szükség szerint megfelelő megoldásokat kell készíteniük. Például azoknak az alkalmazásoknak, amelyek javításműveleteknek teszik ki a gyűjteményeket, figyelembe kell venniük az algoritmikus összetettségi támadások lehetőségét, ha ezek a műveletek elemeket szúrnak be vagy távolítanak el a gyűjtemény elején.
A JSON Patch funkcióinak alkalmazásba való integrálása során felmerülő biztonsági kockázatok minimalizálása érdekében a fejlesztőknek a következőkkel kell rendelkezniük:
- Futtasson átfogó fenyegetésmodelleket saját alkalmazásaikhoz.
- Elhárítja az azonosított fenyegetéseket.
- Kövesse az alábbi szakaszokban javasolt intézkedéseket.
Szolgáltatásmegtagadás (DoS) memóriaerősítéssel
-
Forgatókönyv: Egy rosszindulatú ügyfél olyan műveletet küld,
copyamely többször duplikálja a nagy objektumdiagramokat, ami túlzott memóriahasználathoz vezet. - Hatás: Lehetséges kimenőOf-Memory (OOM) feltételek, ami szolgáltatáskimaradásokat okoz.
-
Mitigation:
- Ellenőrizze a bejövő JSON Patch-dokumentumokat a méret és a struktúra szempontjából, mielőtt hívja a ApplyTo(Object)-t.
- Az érvényesítésnek alkalmazásspecifikusnak kell lennie, de egy példaérvényesítés a következőhöz hasonló lehet:
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();
}
}
Üzleti logika megváltoztatása
- Forgatókönyv: A javításműveletek implicit invariánsokkal (például belső jelzőkkel, azonosítókkal vagy számított mezőkkel) módosíthatják a mezőket, megsértve az üzleti korlátozásokat.
- Hatás: Adatintegritási problémák és nem szándékos alkalmazás viselkedése.
-
Mitigation:
- Használjon POCOS-objektumokat (egyszerű régi CLR-objektumokat) explicit módon definiált, biztonságosan módosítható tulajdonságokkal.
- Kerülje a bizalmas vagy biztonsági szempontból kritikus tulajdonságok felfedését a célobjektumban.
- Ha nem használ POCO-objektumot, ellenőrizze a javított objektumot a műveletek alkalmazása után annak érdekében, hogy az üzleti szabályok és az invariánsok ne sérüljenek.
- Használjon POCOS-objektumokat (egyszerű régi CLR-objektumokat) explicit módon definiált, biztonságosan módosítható tulajdonságokkal.
Hitelesítés és engedélyezés
- Forgatókönyv: A nem hitelesített vagy jogosulatlan ügyfelek rosszindulatú JSON-javításkéréseket küldenek.
- Hatás: Jogosulatlan hozzáférés bizalmas adatok módosításához vagy az alkalmazás viselkedésének megzavarásához.
-
Mitigation:
- A JSON Patch-kéréseket elfogadó végpontok védelme megfelelő hitelesítési és engedélyezési mechanizmusokkal.
- Korlátozza a hozzáférést a megbízható ügyfelekhez vagy a megfelelő engedélyekkel rendelkező felhasználókhoz.
A kód lekérése
Mintakód megtekintése vagy letöltése. (A letöltés módja).
A minta teszteléséhez futtassa az alkalmazást, és küldjön HTTP-kéréseket a következő beállításokkal:
- URL-cím:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - HTTP-metódus:
PATCH - Fejléc:
Content-Type: application/json-patch+json - Törzs: Másolja és illessze be a JSON-javítás dokumentummintáinak egyikét a JSON projektmappából.
További erőforrások
Ez a cikk bemutatja, hogyan kezelheti a JSON-javítás kéréseit egy ASP.NET Core webes API-ban.
Important
A JSON Patch szabvány belső biztonsági kockázatokkal jár. Ez az implementáció nem próbálja enyhíteni ezeket az eredendő biztonsági kockázatokat. A fejlesztő felelőssége annak biztosítása, hogy a JSON Patch-dokumentum biztonságosan alkalmazható legyen a célobjektumra. További információ: A biztonsági kockázatok mérséklése szakasz.
Csomag telepítése
Az ASP.NET Core webes API-ban a JSON Patch támogatás a Newtonsoft.Json alapul, és megköveteli a Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet-csomagot.
A JSON-javítás támogatásának engedélyezése:
Telepítse a
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNuGet-csomagot.Hívja fel: AddNewtonsoftJson. Például:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddNewtonsoftJson(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
AddNewtonsoftJsonAz System.Text.Json JSON-tartalom formázásához használt alapértelmezett bemeneti és kimeneti formátumot cseréli le. Ez a bővítménymetódus a következő MVC-szolgáltatásregisztrációs módszerekkel kompatibilis:
A JsonPatch használatához be kell állítani a fejlécet Content-Type-ről application/json-patch+json-re.
JSON Patch támogatás hozzáadása a System.Text.Json használatakor
A System.Text.Json alapú bemeneti formázó nem támogatja a JSON-javításokat. A JSON-javítás Newtonsoft.Jsontámogatásának hozzáadása a többi bemeneti és kimeneti formátum változatlan maradása mellett:
Telepítse a
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNuGet-csomagot.Frissítés
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(); } }
Az előző kód létrehoz egy példányt NewtonsoftJsonPatchInputFormatter, és beszúrja azt a MvcOptions.InputFormatters gyűjteménybe első bejegyzésként. Ez a regisztrációs sorrend biztosítja, hogy:
-
NewtonsoftJsonPatchInputFormatterJSON Patch-kérelmeket dolgoz fel. - A meglévő
System.Text.Json-alapú bemenetek és formázók dolgozzák fel az összes többi JSON kérést és választ.
Newtonsoft.Json.JsonConvert.SerializeObject A metódussal szerializálhat egy JsonPatchDocument.
PATCH HTTP kérési módszer
A PUT és a PATCH metódusok egy meglévő erőforrás frissítésére szolgálnak. A különbség köztük az, hogy a PUT a teljes erőforrást lecseréli, míg a PATCH csak a módosításokat határozza meg.
JSON-javítás
A JSON-javítás az erőforrásra alkalmazni kívánt frissítések megadására szolgáló formátum. A JSON-javítások dokumentumai műveletek tömbjéből áll. Minden művelet azonosít egy adott típusú módosítást. Ilyen módosítások például tömbelem hozzáadása vagy tulajdonságérték cseréje.
A következő JSON-dokumentumok például egy erőforrást, egy JSON patch-dokumentumot jelölnek az erőforráshoz, valamint a Javításműveletek alkalmazásának eredményét.
Példa erőforrásra
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
Példa JSON-módosításra
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
A fenti JSON-ban:
- A
optulajdonság a művelet típusát jelzi. - A
pathtulajdonság a frissíteni kívánt elemet jelzi. - A
valuetulajdonság az új értéket adja meg.
Erőforrás frissítés után
Az erőforrás az előző JSON Patch-dokumentum alkalmazása után:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
A JSON Patch-dokumentum erőforrásra való alkalmazásával végrehajtott módosítások atomiak. Ha a listában található bármely művelet meghiúsul, a listában egyetlen művelet sem lesz alkalmazva.
Elérési út szintaxisa
A művelet objektum elérési út tulajdonsága perjeleket tartalmaz a szintek között. Például: "/address/zipCode".
A tömbelemek megadására nulla alapú indexek szolgálnak. A addresses tömb első eleme a /addresses/0 helyen található. A add tömb végéig használjon kötőjelet (-) indexszám helyett: /addresses/-.
Operations
Az alábbi táblázat a JSON-javítás specifikációjában meghatározott támogatott műveleteket mutatja be:
| Operation | Notes |
|---|---|
add |
Adjon hozzá egy tulajdonságot vagy tömbelemet. Meglévő tulajdonság esetén: érték beállítása. |
remove |
Távolítson el egy tulajdonságot vagy tömbelemet. |
replace |
Ugyanaz, mint remove, amelyet ugyanazon a helyen add követ. |
move |
Ugyanaz, mint remove a forrásból, majd add a célhelyre a forrásból származó érték használatával. |
copy |
Ugyanaz, mint add a forrásból származó értéket használó célhely. |
test |
Sikerességi állapotkódot ad vissza, ha az érték értéke = path meg van adva value. |
JSON-javítás a ASP.NET Core-ban
A JSON Patch ASP.NET core implementációját a Microsoft.AspNetCore.JsonPatch NuGet csomag biztosítja.
Műveletmetódus kódja
Egy API-vezérlőben a JSON-javítás műveletmetódusa:
- A(z)
HttpPatchattribútummal van megjelölve. - Elfogad egy JsonPatchDocument<TModel>, általában a
[FromBody]. - A módosítások alkalmazásához ApplyTo(Object) hívja meg a módosítási dokumentumot.
Íme egy példa:
[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);
}
}
A mintaalkalmazásból származó kód a következő Customer modellel működik:
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; }
}
A mintaműveleti módszer:
- Létrehoz egy
Customer-t. - Alkalmazza a javítást.
- Az eredményt a válasz törzsében adja vissza.
Egy valós alkalmazásban a kód lekéri az adatokat egy tárolóból, például egy adatbázisból, és frissíti az adatbázist a javítás alkalmazása után.
Modell állapota
Az előző műveletmetódus-példa egy olyan ApplyTo túlterhelt verziót hív meg, amely a modellállapotot az egyik paramétereként fogadja. Ezzel a beállítással hibaüzeneteket kaphat a válaszokban. Az alábbi példa egy művelet 400 hibás kérésre adott test válaszának törzsét mutatja be:
{
"Customer": [
"The current value 'John' at path 'customerName' != test value 'Nancy'."
]
}
Dinamikus objektumok
Az alábbi műveletmetódus-példa bemutatja, hogyan alkalmazhat javításokat dinamikus objektumokra:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
A hozzáadási művelet
- Ha
pathegy tömbelemre mutat: új elemet szúr be a megadottpathelem elé. - Ha
pathegy tulajdonságra mutat: beállítja a tulajdonság értékét. - Ha
pathnem létező helyre mutat:- Ha a javításhoz szükséges erőforrás egy dinamikus objektum: hozzáad egy tulajdonságot.
- Ha a javításhoz szükséges erőforrás statikus objektum: a kérés meghiúsul.
Az alábbi mintajavító dokumentum beállítja CustomerName a tömb értékét, és hozzáad egy Order objektumot a Orders tömb végéhez.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Az eltávolítási művelet
- Ha
pathegy tömbelemre mutat: eltávolítja az elemet. - Ha
pathegy tulajdonságra mutat:- Ha a javításhoz szükséges erőforrás dinamikus objektum: eltávolítja a tulajdonságot.
- Ha a javításhoz szükséges erőforrás statikus objektum:
- Ha a tulajdonság null értékű: null értékűre állítja.
- Ha a tulajdonság nem null értékű, akkor a következőre
default<T>állítja: .
A következő minta javítási dokumentum CustomerName értékét nullává állítja, és törli a Orders[0]-t.
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
A csereművelet
Ez a művelet funkcionálisan megegyezik egy remove , majd egy add-vel.
Az alábbi mintajavító dokumentum beállítja a(z) CustomerName értékét, és a(z) Orders[0] helyére egy új Order objektumot helyez.
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Az áthelyezési művelet
- Ha
pathegy tömbelemre mutat:fromelemet másoljapathelem helyére, majd végrehajt egyremoveműveletet azfromelemen. - Ha
pathegy tulajdonságra mutat: a tulajdonság értékétfromátmásolja a tulajdonságbapath, majd futtat egyremoveműveletet afromtulajdonságon. - Ha
pathnem létező tulajdonságra mutat:- Ha a javításhoz szükséges erőforrás statikus objektum: a kérés meghiúsul.
- Ha a javításhoz szükséges erőforrás egy dinamikus objektum: a tulajdonságot a megadott helyre másolja
from, majd futtat egypathműveletet aremovetulajdonságon.from
A következő mintajavító dokumentum:
- A(z)
Orders[0].OrderNameértékének másolása aCustomerName-re. - Null értékre van adva
Orders[0].OrderName. - Áthelyez
Orders[1]közvetlenülOrders[0]elé.
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
A másolási művelet
Ez a művelet funkcionálisan megegyezik az move utolsó remove lépés nélküli művelettel.
A következő mintajavító dokumentum:
- A(z)
Orders[0].OrderNameértékének másolása aCustomerName-re. - Beszúr egy másolatot a
Orders[1]eléOrders[0].
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
A tesztművelet
Ha a megadott path helyen lévő érték eltér a megadott valueértéktől, a kérés meghiúsul. Ebben az esetben a teljes PATCH-kérés akkor is meghiúsul, ha a javításdokumentum összes többi művelete egyébként sikeres lenne.
A test műveletet gyakran használják a frissítés megelőzésére egyidejűségi ütközés esetén.
A következő mintajavító dokumentumnak nincs hatása, ha a kezdeti érték CustomerName "John", mert a teszt sikertelen:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
A kód lekérése
Mintakód megtekintése vagy letöltése. (A letöltés módja).
A minta teszteléséhez futtassa az alkalmazást, és küldjön HTTP-kéréseket a következő beállításokkal:
- URL-cím:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - HTTP-metódus:
PATCH - Fejléc:
Content-Type: application/json-patch+json - Törzs: Másolja és illessze be a JSON-javítás dokumentummintáinak egyikét a JSON projektmappából.
A biztonsági kockázatok mérséklése
A(z) Microsoft.AspNetCore.JsonPatch csomag Newtonsoft.Json-alapú implementációval való használata esetén elengedhetetlen a lehetséges biztonsági kockázatok megértése és csökkentése. A következő szakaszok ismertetik a JSON-javításhoz kapcsolódó azonosított biztonsági kockázatokat, és ajánlott megoldásokat nyújtanak a csomag biztonságos használatának biztosítása érdekében.
Important
Ez nem a fenyegetések teljes listája. Az alkalmazásfejlesztőknek saját fenyegetésmodell-felülvizsgálatokat kell végezniük az alkalmazásspecifikus átfogó lista meghatározásához, és szükség szerint megfelelő megoldásokat kell készíteniük. Például azoknak az alkalmazásoknak, amelyek javításműveleteknek teszik ki a gyűjteményeket, figyelembe kell venniük az algoritmikus összetettségi támadások lehetőségét, ha ezek a műveletek elemeket szúrnak be vagy távolítanak el a gyűjtemény elején.
Ha átfogó fenyegetésmodelleket futtat saját alkalmazásaikhoz, és kezeli az azonosított fenyegetéseket, miközben az alábbi javasolt megoldásokat követi, ezeknek a csomagoknak a felhasználói a biztonsági kockázatok minimalizálása mellett integrálhatják a JSON Patch funkcióit az alkalmazásaikba.
Szolgáltatásmegtagadás (DoS) memóriaerősítéssel
-
Forgatókönyv: Egy rosszindulatú ügyfél olyan műveletet küld,
copyamely többször duplikálja a nagy objektumdiagramokat, ami túlzott memóriahasználathoz vezet. - Hatás: Lehetséges kimenőOf-Memory (OOM) feltételek, ami szolgáltatáskimaradásokat okoz.
-
Mitigation:
- Ellenőrizze a bejövő JSON Patch-dokumentumokat a méret és a struktúra szempontjából, mielőtt hívja a
ApplyTo-t. - Az ellenőrzésnek alkalmazásspecifikusnak kell lennie, de egy példaérvényesítés a következőhöz hasonló lehet:
- Ellenőrizze a bejövő JSON Patch-dokumentumokat a méret és a struktúra szempontjából, mielőtt hívja a
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();
}
}
Üzleti logika megváltoztatása
- Forgatókönyv: A javításműveletek implicit invariánsokkal (például belső jelzőkkel, azonosítókkal vagy számított mezőkkel) módosíthatják a mezőket, megsértve az üzleti korlátozásokat.
- Hatás: Adatintegritási problémák és nem szándékos alkalmazás viselkedése.
-
Mitigation:
- Olyan POCO-objektumokat használjon, amelyek kifejezetten meghatározott tulajdonságokkal rendelkeznek, amelyek biztonságosan módosíthatók.
- Kerülje a bizalmas vagy biztonsági szempontból kritikus tulajdonságok felfedését a célobjektumban.
- Ha nem használ POCO-objektumot, ellenőrizze a javított objektumot a műveletek alkalmazása után annak biztosítása érdekében, hogy az üzleti szabályok és a változók ne sérüljenek.
Hitelesítés és engedélyezés
- Forgatókönyv: A nem hitelesített vagy jogosulatlan ügyfelek rosszindulatú JSON-javításkéréseket küldenek.
- Hatás: Jogosulatlan hozzáférés bizalmas adatok módosításához vagy az alkalmazás viselkedésének megzavarásához.
-
Mitigation:
- A JSON Patch-kéréseket elfogadó végpontok védelme megfelelő hitelesítési és engedélyezési mechanizmusokkal.
- Korlátozza a hozzáférést a megbízható ügyfelekhez vagy a megfelelő engedélyekkel rendelkező felhasználókhoz.
További erőforrások
Ez a cikk bemutatja, hogyan kezelheti a JSON-javítás kéréseit egy ASP.NET Core webes API-ban.
Important
A JSON Patch szabvány belső biztonsági kockázatokkal jár. Mivel ezek a kockázatok a JSON Patch szabványhoz tartoznak, ez a megvalósítás nem próbálja csökkenteni az eredendő biztonsági kockázatokat. A fejlesztő felelőssége annak biztosítása, hogy a JSON Patch-dokumentum biztonságosan alkalmazható legyen a célobjektumra. További információ: A biztonsági kockázatok mérséklése szakasz.
Csomag telepítése
Ha engedélyezni szeretné a JSON-javítások támogatását az alkalmazásban, hajtsa végre az alábbi lépéseket:
Telepítse a
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNuGet-csomagot.Frissítse a(z)
Startup.ConfigureServicesmetódust a projektben, hogy meghívja AddNewtonsoftJson. Például:services .AddControllersWithViews() .AddNewtonsoftJson();
AddNewtonsoftJson kompatibilis az MVC szolgáltatásregisztrációs módszereivel:
JSON-javítás, AddNewtonsoftJson és System.Text.Json
AddNewtonsoftJson lecseréli az System.Text.Json alapú bemeneti és kimeneti formázókat, amelyeket az összes JSON-tartalom formázásához használnak. A JSON-javítás támogatásának hozzáadásához a többi formázó változatlanul hagyásával Newtonsoft.Jsonfrissítse a projekt metódusát Startup.ConfigureServices az alábbiak szerint:
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();
}
Az előző kódhoz a Microsoft.AspNetCore.Mvc.NewtonsoftJson csomagra és a következő using utasításokra van szükség:
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;
A JsonPatchDocument szerializálásához használja a Newtonsoft.Json.JsonConvert.SerializeObject metódust.
PATCH HTTP kérési módszer
A PUT és a PATCH metódusok egy meglévő erőforrás frissítésére szolgálnak. A különbség köztük az, hogy a PUT a teljes erőforrást lecseréli, míg a PATCH csak a módosításokat határozza meg.
JSON-javítás
A JSON-javítás az erőforrásra alkalmazni kívánt frissítések megadására szolgáló formátum. A JSON-javítások dokumentumai műveletek tömbjéből áll. Minden művelet azonosít egy adott típusú módosítást. Ilyen módosítások például tömbelem hozzáadása vagy tulajdonságérték cseréje.
A következő JSON-dokumentumok például egy erőforrást, egy JSON patch-dokumentumot jelölnek az erőforráshoz, valamint a Javításműveletek alkalmazásának eredményét.
Példa erőforrásra
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
Példa JSON-módosításra
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
A fenti JSON-ban:
- A
optulajdonság a művelet típusát jelzi. - A
pathtulajdonság a frissíteni kívánt elemet jelzi. - A
valuetulajdonság az új értéket adja meg.
Erőforrás frissítés után
Az erőforrás az előző JSON Patch-dokumentum alkalmazása után:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
A JSON Patch-dokumentum erőforrásra való alkalmazásával végrehajtott módosítások atomiak. Ha a listában található bármely művelet meghiúsul, a listában egyetlen művelet sem lesz alkalmazva.
Elérési út szintaxisa
A művelet objektum elérési út tulajdonsága perjeleket tartalmaz a szintek között. Például: "/address/zipCode".
A tömbelemek megadására nulla alapú indexek szolgálnak. A addresses tömb első eleme a /addresses/0 helyen található. A add tömb végéig használjon kötőjelet (-) indexszám helyett: /addresses/-.
Operations
Az alábbi táblázat a JSON-javítás specifikációjában meghatározott támogatott műveleteket mutatja be:
| Operation | Notes |
|---|---|
add |
Adjon hozzá egy tulajdonságot vagy tömbelemet. Meglévő tulajdonság esetén: érték beállítása. |
remove |
Távolítson el egy tulajdonságot vagy tömbelemet. |
replace |
Ugyanaz, mint remove, amelyet ugyanazon a helyen add követ. |
move |
Ugyanaz, mint remove a forrásból, majd add a célhelyre a forrásból származó érték használatával. |
copy |
Ugyanaz, mint add a forrásból származó értéket használó célhely. |
test |
Sikerességi állapotkódot ad vissza, ha az érték értéke = path meg van adva value. |
JSON-javítás a ASP.NET Core-ban
A JSON Patch ASP.NET core implementációját a Microsoft.AspNetCore.JsonPatch NuGet csomag biztosítja.
Műveletmetódus kódja
Egy API-vezérlőben a JSON-javítás műveletmetódusa:
- A(z)
HttpPatchattribútummal van megjelölve. - Elfogad egy
JsonPatchDocument<T>, általában a[FromBody]. - A módosítások alkalmazásához
ApplyTohívja meg a módosítási dokumentumot.
Íme egy példa:
[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);
}
}
A mintaalkalmazásból származó kód a következő Customer modellel működik:
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; }
}
}
A mintaműveleti módszer:
- Létrehoz egy
Customer-t. - Alkalmazza a javítást.
- Az eredményt a válasz törzsében adja vissza.
Egy valós alkalmazásban a kód lekéri az adatokat egy tárolóból, például egy adatbázisból, és frissíti az adatbázist a javítás alkalmazása után.
Modell állapota
Az előző műveletmetódus-példa egy olyan ApplyTo túlterhelt verziót hív meg, amely a modellállapotot az egyik paramétereként fogadja. Ezzel a beállítással hibaüzeneteket kaphat a válaszokban. Az alábbi példa egy művelet 400 hibás kérésre adott test válaszának törzsét mutatja be:
{
"Customer": [
"The current value 'John' at path 'customerName' is not equal to the test value 'Nancy'."
]
}
Dinamikus objektumok
Az alábbi műveletmetódus-példa bemutatja, hogyan alkalmazhat javításokat dinamikus objektumokra:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
A hozzáadási művelet
- Ha
pathegy tömbelemre mutat: új elemet szúr be a megadottpathelem elé. - Ha
pathegy tulajdonságra mutat: beállítja a tulajdonság értékét. - Ha
pathnem létező helyre mutat:- Ha a javításhoz szükséges erőforrás egy dinamikus objektum: hozzáad egy tulajdonságot.
- Ha a javításhoz szükséges erőforrás statikus objektum: a kérés meghiúsul.
Az alábbi mintajavító dokumentum beállítja CustomerName a tömb értékét, és hozzáad egy Order objektumot a Orders tömb végéhez.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Az eltávolítási művelet
- Ha
pathegy tömbelemre mutat: eltávolítja az elemet. - Ha
pathegy tulajdonságra mutat:- Ha a javításhoz szükséges erőforrás dinamikus objektum: eltávolítja a tulajdonságot.
- Ha a javításhoz szükséges erőforrás statikus objektum:
- Ha a tulajdonság null értékű: null értékűre állítja.
- Ha a tulajdonság nem null értékű, akkor a következőre
default<T>állítja: .
A következő minta javítási dokumentum CustomerName értékét nullává állítja, és törli a Orders[0]-t.
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
A csereművelet
Ez a művelet funkcionálisan megegyezik egy remove , majd egy add-vel.
Az alábbi mintajavító dokumentum beállítja a(z) CustomerName értékét, és a(z) Orders[0] helyére egy új Order objektumot helyez.
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Az áthelyezési művelet
- Ha
pathegy tömbelemre mutat:fromelemet másoljapathelem helyére, majd végrehajt egyremoveműveletet azfromelemen. - Ha
pathegy tulajdonságra mutat: a tulajdonság értékétfromátmásolja a tulajdonságbapath, majd futtat egyremoveműveletet afromtulajdonságon. - Ha
pathnem létező tulajdonságra mutat:- Ha a javításhoz szükséges erőforrás statikus objektum: a kérés meghiúsul.
- Ha a javításhoz szükséges erőforrás egy dinamikus objektum: a tulajdonságot a megadott helyre másolja
from, majd futtat egypathműveletet aremovetulajdonságon.from
A következő mintajavító dokumentum:
- A(z)
Orders[0].OrderNameértékének másolása aCustomerName-re. - Null értékre van adva
Orders[0].OrderName. - Áthelyez
Orders[1]közvetlenülOrders[0]elé.
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
A másolási művelet
Ez a művelet funkcionálisan megegyezik az move utolsó remove lépés nélküli művelettel.
A következő mintajavító dokumentum:
- A(z)
Orders[0].OrderNameértékének másolása aCustomerName-re. - Beszúr egy másolatot a
Orders[1]eléOrders[0].
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
A tesztművelet
Ha a megadott path helyen lévő érték eltér a megadott valueértéktől, a kérés meghiúsul. Ebben az esetben a teljes PATCH-kérés akkor is meghiúsul, ha a javításdokumentum összes többi művelete egyébként sikeres lenne.
A test műveletet gyakran használják a frissítés megelőzésére egyidejűségi ütközés esetén.
A következő mintajavító dokumentumnak nincs hatása, ha a kezdeti érték CustomerName "John", mert a teszt sikertelen:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
A kód lekérése
Mintakód megtekintése vagy letöltése. (A letöltés módja).
A minta teszteléséhez futtassa az alkalmazást, és küldjön HTTP-kéréseket a következő beállításokkal:
- URL-cím:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - HTTP-metódus:
PATCH - Fejléc:
Content-Type: application/json-patch+json - Törzs: Másolja és illessze be a JSON-javítás dokumentummintáinak egyikét a JSON projektmappából.