Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makalede, ASP.NET Core web API'sinde JSON Düzeltme Eki isteklerinin nasıl işleneceğini açıklanmaktadır.
ASP.NET Core web API'de JSON Yaması desteği, System.Text.Json serileştirmesine dayanır ve Microsoft.AspNetCore.JsonPatch.SystemTextJson NuGet paketini gerektirir.
JSON Patch standardı nedir?
JSON Patch standardı:
JSON belgesine uygulanacak değişiklikleri açıklamaya yönelik standart bir biçimdir.
RFC 6902'de tanımlanır ve JSON kaynaklarında kısmi güncelleştirmeler gerçekleştirmek için RESTful API'lerinde yaygın olarak kullanılır.
Aşağıdakiler gibi bir JSON belgesini değiştiren işlem dizisini açıklar:
addremovereplacemovecopytest
Web uygulamalarında JSON Patch genellikle bir kaynağın kısmi güncelleştirmelerini gerçekleştirmek için PATCH işleminde kullanılır. İstemciler, bir güncelleştirme için kaynağın tamamını göndermek yerine yalnızca değişiklikleri içeren bir JSON Düzeltme Eki belgesi gönderebilir. Yama yapmak, yük boyutunu azaltır ve verimliliği artırır.
JSON Düzeltme Eki standardına genel bakış için bkz. jsonpatch.com.
ASP.NET Core web API'de JSON Patch'in desteklenmesi
ASP.NET Core web API'sindeki JSON Düzeltme Eki desteği, .NET 10'dan başlayarak System.Text.Json serileştirmeyi temel alır. Microsoft.AspNetCore.JsonPatch, System.Text.Json serileştirmesine dayalı olarak uygulanır. Bu özellik:
-
Microsoft.AspNetCore.JsonPatch.SystemTextJsonNuGet paketini gerektirir. - Modern .NET uygulamalarıyla uyumlu olan System.Text.Json kitaplığı, .NET için optimize edilmiştir.
- Eski
Newtonsoft.Jsontabanlı uygulamaya kıyasla daha iyi performans ve azaltılmış bellek kullanımı sağlar. EskiNewtonsoft.Jsontabanlı uygulama hakkında daha fazla bilgi için bu makalenin .NET 9 sürümüne bakın.
Note
Microsoft.AspNetCore.JsonPatch serileştirmesine dayalı System.Text.Json uygulaması, eski Newtonsoft.Json tabanlı uygulamanın doğrudan bir ikamesi değildir. gibi ExpandoObjectdinamik türleri desteklemez.
Important
JSON Patch standardının doğal güvenlik riskleri vardır. Bu riskler JSON Patch standardına bağlı olduğundan, ASP.NET Core uygulaması doğal güvenlik risklerini azaltmaya çalışmaz. JSON Patch belgesinin hedef nesneye uygulanmasının güvenli olduğundan emin olmak geliştiricinin sorumluluğundadır. Daha fazla bilgi için Güvenlik Risklerini Azaltma bölümüne bakın.
JSON Düzeltme Eki desteğini System.Text.Json ile etkinleştirin
JSON Yaması desteğini System.Text.Json etkinleştirmek için Microsoft.AspNetCore.JsonPatch.SystemTextJson NuGet paketini yükleyin.
dotnet add package Microsoft.AspNetCore.JsonPatch.SystemTextJson
Bu paket, JsonPatchDocument<TModel> sınıfını, TModel türü nesneler için JSON Patch belgesini temsil etmek üzere ve System.Text.Json kullanılarak JSON Patch belgelerinin seri hale getirilmesi ve seri durumdan çıkarılması için özel mantığı sağlar.
JsonPatchDocument<TModel> sınıfının anahtar yöntemi, düzeltme eki işlemlerini ApplyTo(Object) türündeki bir hedef nesneye uygulayan TModel yöntemidir.
JSON Patch uygulayan Minimal API PATCH uç noktası
Minimal API'de JSON Patch için PATCH uç noktası:
- Yolu tanımlamak için kullanır
MapPatch. - Bir JsonPatchDocument<TModel> parametreyi kabul eder.
- Değişiklikleri uygulamak için yama belgesinde ApplyTo(Object) çağırır.
Örnek Minimal API PATCH uç noktası
group.MapPatch("/{id}", async Task<Results<Ok<Customer>,ValidationProblem,NotFound<ProblemDetails>>> (AppDb db, string id,
JsonPatchDocument<Customer> patchDoc) =>
{
var customer = await db.Customers.Include(c => c.Orders).FirstOrDefaultAsync(c => c.Id == id);
if (customer is null)
{
return TypedResults.NotFound<ProblemDetails>(new ());
}
if (patchDoc != null)
{
Dictionary<string, string[]>? errors = null;
patchDoc.ApplyTo(customer, 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)
{
return TypedResults.ValidationProblem(errors);
}
// Only save if there are no errors
await db.SaveChangesAsync();
}
return TypedResults.Ok(customer);
})
.Accepts<JsonPatchDocument<Customer>>("application/json-patch+json");
Örnek uygulamadaki bu kod aşağıdakilerle Customer ve Order modelleriyle çalışır:
using System.ComponentModel.DataAnnotations;
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();
}
}
Örnek PATCH uç noktasının temel adımları:
-
Müşteriyi Alma:
- Uç nokta, sağlanan
Customeröğesini kullanarak veritabanındanAppDbbiridnesne alır. - Hiçbir
Customernesnesi bulunmazsa,TypedResults.NotFound()aracılığıyla404 Not Foundyanıtı döndürür.
- Uç nokta, sağlanan
-
JSON Düzeltme Eki Uygula:
-
ApplyTo(Object) yöntemi,
patchDociçindeki JSON Patch işlemlerini alınanCustomernesnesine uygular. - Düzeltme eki uygulaması sırasında geçersiz işlemler veya çakışmalar gibi hatalar oluşursa, hata işleme temsilcisi bunları yakalar. Bu temsilci, hata iletilerini etkilenen nesnenin tür adıyla anahtarlanmış bir sözlükte toplar.
-
ApplyTo(Object) yöntemi,
-
Doğrulama hatalarını döndürme:
- Hata işleme temsilcisi düzeltme eki uygulaması sırasında hataları yakalarsa, uç nokta aracılığıyla
ValidationProblemhata ayrıntılarını içeren birTypedResults.ValidationProblem(errors)yanıt döndürür.
- Hata işleme temsilcisi düzeltme eki uygulaması sırasında hataları yakalarsa, uç nokta aracılığıyla
-
Güncelleştirilmiş Müşteriyi kaydedin ve iade edin:
- Düzeltme eki hata olmadan başarıyla uygulanırsa, değişiklikler veritabanına kaydedilir ve uç nokta aracılığıyla
CustomergüncelleştirilmişTypedResults.Ok(customer)nesneyi döndürür.
- Düzeltme eki hata olmadan başarıyla uygulanırsa, değişiklikler veritabanına kaydedilir ve uç nokta aracılığıyla
Örnek hata yanıtı
Aşağıdaki örnek, belirtilen yol geçersiz olduğunda JSON Patch işlemi için doğrulama sorunu yanıtının gövdesini gösterir:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Customer": [
"The target location specified by path segment 'foobar' was not found."
]
}
}
Nesneye JSON Düzeltme Eki belgesi uygulama
Aşağıdaki örnekler, JSON Patch belgesini bir nesneye uygulamak için ApplyTo(Object) yönteminin nasıl kullanılacağını göstermektedir.
Örnek: Bir JsonPatchDocument<TModel> nesneye uygulayın
Aşağıdaki örnekte gösterilmiştir:
-
add,replaceveremoveişlemleri. - İç içe geçmiş özelliklerde işlemler.
- Diziye yeni öğe ekleme.
- JSON yama belgesinde JSON Dize Enum Dönüştürücüsü kullanma.
// 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));
Önceki örnekte güncelleştirilmiş nesnenin aşağıdaki çıkışı elde edilir:
{
"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"
}
]
}
ApplyTo(Object) yöntemi, işleme System.Text.Json kurallarını ve seçeneklerini, aşağıdaki seçenekler tarafından denetlenen davranış da dahil olmak üzere, JsonPatchDocument<TModel> için geçerli olan kurallar ve seçenekleri izler.
- JsonNumberHandling: Sayısal özelliklerin dizelerden okunup okunmadığı.
- PropertyNameCaseInsensitive: Özellik adlarının büyük/küçük harfe duyarlı olup olmadığı.
System.Text.Json ve yeni JsonPatchDocument<TModel> uygulaması arasındaki ana farklar:
- Hedef nesnenin bildirilmiş türü değil, çalışma zamanındaki türü, hangi özellikleri ApplyTo(Object) yamanacağını belirler.
- System.Text.Json seri durumdan çıkarma, uygun özellikleri tanımlamak için bildirilen türe dayanır.
Örnek: Hata işleme ile JsonPatchDocument'i uygulama
JSON Düzeltme Eki belgesi uygulanırken çeşitli hatalar oluşabilir. Örneğin, hedef nesne belirtilen özelliğe sahip olmayabilir veya belirtilen değer özellik türüyle uyumsuz olabilir.
JSON Patch , belirtilen bir değerin test hedef özelliğe eşit olup olmadığını denetleyen işlemi destekler. Aksi takdirde bir hata döndürür.
Aşağıdaki örnekte bu hataların düzgün bir şekilde nasıl işleneceğini gösterilmektedir.
Important
ApplyTo(Object) yöntemine aktarılan nesne doğrudan değiştirilir. İşlemlerden herhangi biri başarısız olursa, değişiklikleri atmak çağırıcının sorumluluğundadır.
// 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));
Önceki örnekte aşağıdaki çıkış elde edilir:
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": []
}
Güvenlik risklerini azaltma
Paketi kullanırken Microsoft.AspNetCore.JsonPatch.SystemTextJson olası güvenlik risklerini anlamak ve azaltmak kritik önem taşır. Aşağıdaki bölümlerde JSON Düzeltme Eki ile ilişkili tanımlanan güvenlik riskleri özetlenmiştir ve paketin güvenli kullanımını sağlamak için önerilen risk azaltmaları sağlanır.
Important
Bu, kapsamlı bir tehdit listesi değildir. Uygulama geliştiricileri, uygulamaya özgü kapsamlı bir liste belirlemek ve gerektiğinde uygun risk azaltmaları bulmak için kendi tehdit modeli incelemelerini yapmalıdır. Örneğin, koleksiyonları düzeltme eki işlemlerine sunan uygulamalar, bu işlemlerin koleksiyonun başına öğe eklemesi veya kaldırması durumunda algoritmasal karmaşıklık saldırıları olasılığını göz önünde bulundurmalıdır.
JSON Patch işlevselliğini uygulamalarıyla tümleştirirken güvenlik risklerini en aza indirmek için geliştiriciler şunları yapmalıdır:
- Kendi uygulamaları için kapsamlı tehdit modelleri çalıştırın.
- Tanımlanan tehditleri ele alın.
- Aşağıdaki bölümlerde önerilen azaltmaları izleyin.
Bellek amplifikasyonu yoluyla Hizmet Reddi (DoS)
-
Senaryo: Kötü amaçlı istemci, büyük nesne grafiklerini birden çok kez çoğaltan ve aşırı bellek tüketimine yol açan bir
copyişlem gönderir. - Etki: Hizmet kesintilerine neden olan olası Out-Of-Memory (OOM) koşulları.
-
Mitigation:
- ** ApplyTo(Object) çağırmadan önce gelen JSON Patch belgelerini boyut ve yapı açısından doğrulayın.
- Doğrulamanın uygulamaya özgü olması gerekir, ancak örnek bir doğrulama aşağıdakine benzer olabilir:
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();
}
}
İş mantığının kötüye kullanılması
- Senaryo: Yama işlemleri, iş kısıtlamalarını ihlal ederek alanları örtük sabit değerlerle (örneğin, iç bayraklar, kimlikler veya hesaplanan alanlar) işleyebilir.
- Etki: Veri bütünlüğü sorunları ve istenmeyen uygulama davranışı.
-
Mitigation:
- Değiştirilmesi güvenli olan açıkça tanımlanmış özelliklerle POCO'ları (Düz Eski CLR Nesneleri) kullanın.
- Hedef nesnede hassas veya güvenlik açısından kritik özellikleri ortaya çıkarmaktan kaçının.
- POCO nesnesi kullanılmıyorsa, işlemleri uyguladıktan sonra yaması yapılmış nesneyi doğrulayarak iş kurallarının ve değişmezlerin ihlal edilmediğinden emin olun.
- Değiştirilmesi güvenli olan açıkça tanımlanmış özelliklerle POCO'ları (Düz Eski CLR Nesneleri) kullanın.
Kimlik doğrulaması ve yetkilendirme
- Senaryo: Kimliği doğrulanmamış veya yetkisiz istemciler kötü amaçlı JSON Düzeltme Eki istekleri gönderir.
- Etki: Hassas verileri değiştirmek veya uygulama davranışını kesintiye uğratmak için yetkisiz erişim.
-
Mitigation:
- Uygun kimlik doğrulama ve yetkilendirme mekanizmalarını kullanarak JSON Düzeltme Eki isteklerini kabul eden uç noktaları koruyun.
- Erişimi güvenilen istemcilere veya uygun izinlere sahip kullanıcılara kısıtlayın.
Kodu alın
Örnek kodu görüntüleyin veya indirme. (Nasıl indirilir).
Örneği test etmek için uygulamayı çalıştırın ve eklenen .http dosyayı kullanarak HTTP istekleri gönderin.
Ek kaynaklar
Bu makalede, ASP.NET Core web API'sinde JSON Düzeltme Eki isteklerinin nasıl işleneceğini açıklanmaktadır.
Important
JSON Patch standardının doğal güvenlik riskleri vardır. Bu uygulama , bu doğal güvenlik risklerini azaltmaya çalışmaz. JSON Patch belgesinin hedef nesneye uygulanmasının güvenli olduğundan emin olmak geliştiricinin sorumluluğundadır. Daha fazla bilgi için Güvenlik Risklerini Azaltma bölümüne bakın.
Paket yükleme
ASP.NET Core web API'sindeki JSON Patch desteği, Newtonsoft.Json öğesine dayanır ve Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet paketini gerektirir.
JSON Düzeltme Eki desteğini etkinleştirmek için:
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNuGet paketini yükleyin.AddNewtonsoftJson çağrısı yapın. Örneğin:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddNewtonsoftJson(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
AddNewtonsoftJson, tüm JSON içeriğini biçimlendirmek için kullanılan varsayılan System.Text.Json tabanlı giriş ve çıkış biçimlendiricilerinin yerini alır. Bu uzantı yöntemi aşağıdaki MVC hizmet kayıt yöntemleriyle uyumludur:
JsonPatch, Content-Type üst bilgisinin application/json-patch+json olarak ayarlanmasını gerektirir.
System.Text.Json kullanırken JSON Patch desteği ekleyin
System.Text.Json tabanlı girdi biçimlendiricisi JSON Patch'i desteklemez.
Newtonsoft.Json kullanarak JSON Patch desteği eklemek ve diğer giriş ve çıkış biçimlendiricilerini değiştirmeden bırakmak için:
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNuGet paketini yükleyin.Güncelle
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(); } }
Yukarıdaki kod bir örneği NewtonsoftJsonPatchInputFormatter oluşturur ve bunu koleksiyondaki MvcOptions.InputFormatters ilk girdi olarak ekler. Bu kayıt sırası aşağıdakilerin sağlanmasını sağlar:
-
NewtonsoftJsonPatchInputFormatterJSON Patch isteklerini işler. - Mevcut
System.Text.Jsontabanlı giriş ve biçimlendiriciler diğer tüm JSON isteklerini ve yanıtlarını işler.
JsonPatchDocument öğesini serileştirmek için Newtonsoft.Json.JsonConvert.SerializeObject yöntemini kullanın.
PATCH HTTP istek yöntemi
PUT ve PATCH yöntemleri, mevcut bir kaynağı güncelleştirmek için kullanılır. Aralarındaki fark, PUT'nin kaynağın tamamının yerini aldığı, PATCH'nin ise yalnızca değişiklikleri belirttiğidir.
JSON Patch
JSON Patch, bir kaynağa uygulanacak güncelleştirmeleri belirtmek için kullanılan bir biçimdir. JSON Patch belgesinde bir dizi işlem vardır. Her işlem belirli bir değişiklik türünü tanımlar. Dizi öğesi ekleme veya özellik değerini değiştirme gibi değişikliklere örnek olarak verilebilir.
Örneğin, aşağıdaki JSON belgeleri bir kaynağı, kaynak için JSON Patch belgesini ve Patch işlemlerinin uygulanmasının sonucunu temsil eder.
Kaynak örneği
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
JSON düzeltme eki örneği
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Yukarıdaki JSON kodunda:
-
opözelliği, işlemin türünü gösterir. -
pathözelliği, güncelleştirilecek öğeyi gösterir. -
valueözelliği yeni değeri sağlar.
Yama sonrası kaynak
Yukarıdaki JSON Düzeltme Eki belgesini uyguladıktan sonraki kaynak aşağıdadır:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Bir kaynağa JSON Patch belgesi uygulanarak yapılan değişiklikler atomiktir. Listedeki herhangi bir işlem başarısız olursa, listedeki hiçbir işlem uygulanmaz.
Yol söz dizimi
İşlem nesnesinin path özelliğinde düzeyleri ayıran eğik çizgiler bulunur. Örneğin, "/address/zipCode".
Dizi öğelerini belirtmek için sıfır tabanlı dizinler kullanılır. Dizinin ilk öğesi addresses konumunda /addresses/0olacaktır. Dizinin add sonuna kadar dizin numarası yerine kısa çizgi (-) kullanın: /addresses/-.
Operations
Aşağıdaki tabloda JSON Düzeltme Eki belirtiminde tanımlandığı gibi desteklenen işlemler gösterilmektedir:
| Operation | Notes |
|---|---|
add |
Özellik veya dizi öğesi ekleyin. Mevcut özellik için: değeri ayarlayın. |
remove |
Bir özelliği veya dizi öğesini kaldırın. |
replace |
remove ile aynı, ardından aynı konumda add gelir. |
move |
Kaynaktan remove ile aynı; ardından, kaynaktan alınan değer kullanılarak hedefe add. |
copy |
Kaynakta bulunan değeri kullanarak hedefe add ile aynıdır. |
test |
path konumundaki değer, verilen value değerine eşitse başarı durum kodunu döndürür. |
ASP.NET Core’da JSON Patch
JSON Patch'in ASP.NET Core uygulaması Microsoft.AspNetCore.JsonPatch NuGet paketinde sağlanır.
Eylem yöntemi kodu
Bir API denetleyicisinde JSON Patch için bir eylem metodu:
-
HttpPatchözniteliği ile ek açıklama eklenir. - Genellikle
[FromBody]ile birlikte bir JsonPatchDocument<TModel> kabul eder. - Değişiklikleri uygulamak için yama belgesinde ApplyTo(Object) çağırır.
Bir örnek aşağıda verilmiştir:
[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);
}
}
Örnek uygulamadaki bu kod aşağıdaki Customer modelle çalışır:
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; }
}
Örnek eylem yöntemi:
- bir
Customeroluşturur. - Yamayı uygular.
- Yanıtın gövdesindeki sonucu döndürür.
Gerçek bir uygulamada kod, verileri veritabanı gibi bir depodan alır ve düzeltme ekini uyguladıktan sonra veritabanını güncelleştirir.
Model durumu
Yukarıdaki eylem yöntemi örneği, parametrelerinden biri olarak model durumunu alan ApplyTo aşırı yüklemelerinden birini çağırır. Bu seçenekle yanıtlarda hata iletileri alabilirsiniz. Aşağıdaki örnek, test işlemi için 400 Hatalı İstek yanıt gövdesini gösterir:
{
"Customer": [
"The current value 'John' at path 'customerName' != test value 'Nancy'."
]
}
Dinamik nesneler
Aşağıdaki eylem yöntemi örneği, bir dinamik nesneye düzeltme ekinin nasıl uygulanacağını gösterir:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Ekleme işlemi
- Bir dizi öğesine işaret ederse
path: tarafındanpathbelirtilen öğeden önce yeni öğe ekler. - Bir özelliğe işaret ederse
path: özellik değerini ayarlar. - Var olmayan bir konuma işaret ederse
path:- Yama uygulanacak kaynak dinamik bir nesneyse: bir özellik ekler.
- Düzeltme eki uygulanacak kaynak statik bir nesneyse, istek başarısız olur.
Aşağıdaki örnek yama belgesi, CustomerName değerini ayarlar ve Orders dizisinin sonuna bir Order nesnesi ekler.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Kaldırma işlemi
- Bir dizi öğesine işaret ederse
path: öğesini kaldırır. - Bir özelliğe işaret ederse
path:- Yamalanacak kaynak dinamik bir nesneyse: özellik kaldırılır.
- Yama uygulanacak kaynak statik bir nesneyse:
- Özellik null olabilir durumdaysa: null olarak ayarlar.
- Özellik null atanamaz ise, onu
default<T>değerine ayarlar.
Aşağıdaki örnek yama belgesi, CustomerName öğesini null olarak ayarlar ve Orders[0] öğesini siler:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Değiştirme işlemi
Bu işlem, işlevsel olarak, bir remove işleminin ardından bir add işlemi gerçekleştirmekle aynıdır.
Aşağıdaki örnek yama belgesi, CustomerName değerini ayarlar ve Orders[0] öğesini yeni bir Order nesnesiyle değiştirir:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Taşıma işlemi
-
pathbir dizi öğesine işaret ediyorsa:fromöğesinipathöğesinin konumuna kopyalar, ardındanfromöğesi üzerinde birremoveişlemi yürütür. - Eğer
pathbir özelliğe işaret ediyorsa:fromözelliğinin değerinipathözelliğine kopyalar, ardındanfromözelliği üzerinderemoveişlemi çalıştırır. - Var olmayan bir özelliğe işaret ederse
path:- Düzeltme eki uygulanacak kaynak statik bir nesneyse, istek başarısız olur.
- Yama uygulanacak kaynak dinamik bir nesneyse:
fromözelliğini,pathtarafından belirtilen konuma kopyalar; ardındanfromözelliği üzerinde birremoveişlemi çalıştırır.
Aşağıdaki örnek düzeltme eki belgesi:
-
Orders[0].OrderNamedeğeriniCustomerNameöğesine kopyalar. -
Orders[0].OrderName'ı null olarak ayarlar. -
Orders[1]öğesiniOrders[0]öğesinden önce taşır.
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Kopyalama işlemi
Bu işlem işlevsel olarak son move adım olmadan bir remove işlemle aynıdır.
Aşağıdaki örnek düzeltme eki belgesi:
-
Orders[0].OrderNamedeğeriniCustomerNamekonumuna kopyalar. -
Orders[1]öğesinin bir kopyasınıOrders[0]öğesinden önce ekler.
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Test işlemi
tarafından path belirtilen konumdaki değer, içinde valuesağlanan değerden farklıysa istek başarısız olur. Bu durumda düzeltme eki belgesindeki diğer tüm işlemler başarılı olsa bile PATCH isteğinin tamamı başarısız olur.
İşlem test genellikle eşzamanlılık çakışması olduğunda güncelleştirme yapılmasını önlemek için kullanılır.
Aşağıdaki örnek düzeltme eki belgesinin ilk değeri CustomerName "John" ise hiçbir etkisi yoktur, çünkü test başarısız olur:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Kodu alın
Örnek kodu görüntüleyin veya indirme. (Nasıl indirilir).
Örneği test etmek için uygulamayı çalıştırın ve aşağıdaki ayarlarla HTTP istekleri gönderin:
- URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - HTTP yöntemi:
PATCH - Üstbilgi:
Content-Type: application/json-patch+json - Gövde: JSON proje klasöründeki JSON düzeltme eki belge örneklerinden birini kopyalayıp yapıştırın.
Güvenlik risklerini azaltma
Microsoft.AspNetCore.JsonPatch paketini Newtonsoft.Json tabanlı uygulamayla kullanırken olası güvenlik risklerini anlamak ve azaltmak kritik önem taşır. Aşağıdaki bölümlerde JSON Düzeltme Eki ile ilişkili tanımlanan güvenlik riskleri özetlenmiştir ve paketin güvenli kullanımını sağlamak için önerilen risk azaltmaları sağlanır.
Important
Bu, kapsamlı bir tehdit listesi değildir. Uygulama geliştiricileri, uygulamaya özgü kapsamlı bir liste belirlemek ve gerektiğinde uygun risk azaltmaları bulmak için kendi tehdit modeli incelemelerini yapmalıdır. Örneğin, koleksiyonları düzeltme eki işlemlerine sunan uygulamalar, bu işlemlerin koleksiyonun başına öğe eklemesi veya kaldırması durumunda algoritmasal karmaşıklık saldırıları olasılığını göz önünde bulundurmalıdır.
Bu paketlerin tüketicileri, kendi uygulamaları için kapsamlı tehdit modelleri çalıştırarak ve tanımlanan tehditleri ele alırken aşağıdaki önerilen azaltmaları izleyerek, güvenlik risklerini en aza indirirken JSON Patch işlevselliğini uygulamalarıyla tümleştirebilir.
Bellek amplifikasyonu yoluyla Hizmet Reddi (DoS)
-
Senaryo: Kötü amaçlı istemci, büyük nesne grafiklerini birden çok kez çoğaltan ve aşırı bellek tüketimine yol açan bir
copyişlem gönderir. - Etki: Hizmet kesintilerine neden olan olası Out-Of-Memory (OOM) koşulları.
-
Mitigation:
- **
ApplyToçağırmadan önce gelen JSON Patch belgelerini boyut ve yapı açısından doğrulayın. - Doğrulamanın uygulamaya özgü olması gerekir, ancak örnek bir doğrulama aşağıdakine benzer olabilir:
- **
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();
}
}
İş Mantığı Bozulması
- Senaryo: Yama işlemleri, iş kısıtlamalarını ihlal ederek alanları örtük sabit değerlerle (örneğin, iç bayraklar, kimlikler veya hesaplanan alanlar) işleyebilir.
- Etki: Veri bütünlüğü sorunları ve istenmeyen uygulama davranışı.
-
Mitigation:
- Değiştirilmesi güvenli olan açıkça tanımlanmış özelliklere sahip POCO nesnelerini kullanın.
- Hedef nesnede hassas veya güvenlik açısından kritik özellikleri ortaya çıkarmaktan kaçının.
- PoCO nesnesi kullanılmazsa, iş kurallarının ve sabitlerin ihlal edilmediğinden emin olmak için işlemler uygulandıktan sonra değişiklik yapılan nesneyi doğrulayın.
Kimlik doğrulaması ve yetkilendirme
- Senaryo: Kimliği doğrulanmamış veya yetkisiz istemciler kötü amaçlı JSON Düzeltme Eki istekleri gönderir.
- Etki: Hassas verileri değiştirmek veya uygulama davranışını kesintiye uğratmak için yetkisiz erişim.
-
Mitigation:
- Uygun kimlik doğrulama ve yetkilendirme mekanizmalarıyla JSON Düzeltme Eki isteklerini kabul eden uç noktaları koruyun.
- Erişimi güvenilen istemcilere veya uygun izinlere sahip kullanıcılara kısıtlayın.
Ek kaynaklar
Bu makalede, ASP.NET Core web API'sinde JSON Düzeltme Eki isteklerinin nasıl işleneceğini açıklanmaktadır.
Important
JSON Patch standardının doğal güvenlik riskleri vardır. Bu riskler JSON Düzeltme Eki standardına bağlı olduğundan, bu uygulama doğal güvenlik risklerini azaltmaya çalışmaz. JSON Patch belgesinin hedef nesneye uygulanmasının güvenli olduğundan emin olmak geliştiricinin sorumluluğundadır. Daha fazla bilgi için Güvenlik Risklerini Azaltma bölümüne bakın.
Paket yükleme
Uygulamanızda JSON Düzeltme Eki desteğini etkinleştirmek için aşağıdaki adımları tamamlayın:
Microsoft.AspNetCore.Mvc.NewtonsoftJsonNuGet paketini yükleyin.Projenin
Startup.ConfigureServicesyöntemini, AddNewtonsoftJson çağıracak şekilde güncelleştirin. Örneğin:services .AddControllersWithViews() .AddNewtonsoftJson();
AddNewtonsoftJson MVC hizmet kayıt yöntemleriyle uyumludur:
JSON Patch, AddNewtonsoftJson ve System.Text.Json
AddNewtonsoftJson
System.Text.Json, tüm JSON içeriğini biçimlendirmek için kullanılan tabanlı giriş ve çıkış biçimlendiricilerinin yerini alır.
Newtonsoft.Json kullanarak JSON Patch desteği eklemek ve diğer biçimlendiricileri değiştirmeden bırakmak için, projenin Startup.ConfigureServices yöntemini aşağıdaki gibi güncelleştirin:
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();
}
Yukarıdaki kod, Microsoft.AspNetCore.Mvc.NewtonsoftJson paketini ve aşağıdaki using deyimlerini gerektirir:
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 JsonPatchDocument'ı seri hale getirmek için yöntemini kullanın.
PATCH HTTP istek yöntemi
PUT ve PATCH yöntemleri, mevcut bir kaynağı güncelleştirmek için kullanılır. Aralarındaki fark, PUT'nin kaynağın tamamının yerini aldığı, PATCH'nin ise yalnızca değişiklikleri belirttiğidir.
JSON Patch
JSON Patch, bir kaynağa uygulanacak güncelleştirmeleri belirtmek için kullanılan bir biçimdir. JSON Patch belgesinde bir dizi işlem vardır. Her işlem belirli bir değişiklik türünü tanımlar. Dizi öğesi ekleme veya özellik değerini değiştirme gibi değişikliklere örnek olarak verilebilir.
Örneğin, aşağıdaki JSON belgeleri bir kaynağı, kaynak için JSON Patch belgesini ve Patch işlemlerinin uygulanmasının sonucunu temsil eder.
Kaynak örneği
{
"customerName": "John",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
}
]
}
JSON düzeltme eki örneği
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Yukarıdaki JSON kodunda:
-
opözelliği, işlemin türünü gösterir. -
pathözelliği, güncelleştirilecek öğeyi gösterir. -
valueözelliği yeni değeri sağlar.
Yama sonrası kaynak
Yukarıdaki JSON Düzeltme Eki belgesini uyguladıktan sonraki kaynak aşağıdadır:
{
"customerName": "Barry",
"orders": [
{
"orderName": "Order0",
"orderType": null
},
{
"orderName": "Order1",
"orderType": null
},
{
"orderName": "Order2",
"orderType": null
}
]
}
Bir kaynağa JSON Patch belgesi uygulanarak yapılan değişiklikler atomiktir. Listedeki herhangi bir işlem başarısız olursa, listedeki hiçbir işlem uygulanmaz.
Yol söz dizimi
İşlem nesnesinin path özelliğinde düzeyleri ayıran eğik çizgiler bulunur. Örneğin, "/address/zipCode".
Dizi öğelerini belirtmek için sıfır tabanlı dizinler kullanılır. Dizinin ilk öğesi addresses konumunda /addresses/0olacaktır. Dizinin add sonuna kadar dizin numarası yerine kısa çizgi (-) kullanın: /addresses/-.
Operations
Aşağıdaki tabloda JSON Düzeltme Eki belirtiminde tanımlandığı gibi desteklenen işlemler gösterilmektedir:
| Operation | Notes |
|---|---|
add |
Özellik veya dizi öğesi ekleyin. Mevcut özellik için: değeri ayarlayın. |
remove |
Bir özelliği veya dizi öğesini kaldırın. |
replace |
remove ile aynı, ardından aynı konumda add gelir. |
move |
Kaynaktan remove ile aynı; ardından, kaynaktan alınan değer kullanılarak hedefe add. |
copy |
Kaynakta bulunan değeri kullanarak hedefe add ile aynıdır. |
test |
path konumundaki değer, verilen value değerine eşitse başarı durum kodunu döndürür. |
ASP.NET Core’da JSON Patch
JSON Patch'in ASP.NET Core uygulaması Microsoft.AspNetCore.JsonPatch NuGet paketinde sağlanır.
Eylem yöntemi kodu
Bir API denetleyicisinde JSON Patch için bir eylem metodu:
-
HttpPatchözniteliği ile ek açıklama eklenir. - Genellikle
[FromBody]ile birlikte birJsonPatchDocument<T>kabul eder. - Değişiklikleri uygulamak için yama belgesinde
ApplyToçağırır.
Bir örnek aşağıda verilmiştir:
[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);
}
}
Örnek uygulamadaki bu kod aşağıdaki Customer modelle çalışır:
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; }
}
}
Örnek eylem yöntemi:
- bir
Customeroluşturur. - Yamayı uygular.
- Yanıtın gövdesindeki sonucu döndürür.
Gerçek bir uygulamada kod, verileri veritabanı gibi bir depodan alır ve düzeltme ekini uyguladıktan sonra veritabanını güncelleştirir.
Model durumu
Yukarıdaki eylem yöntemi örneği, parametrelerinden biri olarak model durumunu alan ApplyTo aşırı yüklemelerinden birini çağırır. Bu seçenekle yanıtlarda hata iletileri alabilirsiniz. Aşağıdaki örnek, test işlemi için 400 Hatalı İstek yanıt gövdesini gösterir:
{
"Customer": [
"The current value 'John' at path 'customerName' is not equal to the test value 'Nancy'."
]
}
Dinamik nesneler
Aşağıdaki eylem yöntemi örneği, bir dinamik nesneye düzeltme ekinin nasıl uygulanacağını gösterir:
[HttpPatch]
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
{
dynamic obj = new ExpandoObject();
patch.ApplyTo(obj);
return Ok(obj);
}
Ekleme işlemi
- Bir dizi öğesine işaret ederse
path: tarafındanpathbelirtilen öğeden önce yeni öğe ekler. - Bir özelliğe işaret ederse
path: özellik değerini ayarlar. - Var olmayan bir konuma işaret ederse
path:- Yama uygulanacak kaynak dinamik bir nesneyse: bir özellik ekler.
- Düzeltme eki uygulanacak kaynak statik bir nesneyse, istek başarısız olur.
Aşağıdaki örnek yama belgesi, CustomerName değerini ayarlar ve Orders dizisinin sonuna bir Order nesnesi ekler.
[
{
"op": "add",
"path": "/customerName",
"value": "Barry"
},
{
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Kaldırma işlemi
- Bir dizi öğesine işaret ederse
path: öğesini kaldırır. - Bir özelliğe işaret ederse
path:- Yamalanacak kaynak dinamik bir nesneyse: özellik kaldırılır.
- Yama uygulanacak kaynak statik bir nesneyse:
- Özellik null olabilir durumdaysa: null olarak ayarlar.
- Özellik null atanamaz ise, onu
default<T>değerine ayarlar.
Aşağıdaki örnek yama belgesi, CustomerName öğesini null olarak ayarlar ve Orders[0] öğesini siler:
[
{
"op": "remove",
"path": "/customerName"
},
{
"op": "remove",
"path": "/orders/0"
}
]
Değiştirme işlemi
Bu işlem, işlevsel olarak, bir remove işleminin ardından bir add işlemi gerçekleştirmekle aynıdır.
Aşağıdaki örnek yama belgesi, CustomerName değerini ayarlar ve Orders[0] öğesini yeni bir Order nesnesiyle değiştirir:
[
{
"op": "replace",
"path": "/customerName",
"value": "Barry"
},
{
"op": "replace",
"path": "/orders/0",
"value": {
"orderName": "Order2",
"orderType": null
}
}
]
Taşıma işlemi
-
pathbir dizi öğesine işaret ediyorsa:fromöğesinipathöğesinin konumuna kopyalar, ardındanfromöğesi üzerinde birremoveişlemi yürütür. - Eğer
pathbir özelliğe işaret ediyorsa:fromözelliğinin değerinipathözelliğine kopyalar, ardındanfromözelliği üzerinderemoveişlemi çalıştırır. - Var olmayan bir özelliğe işaret ederse
path:- Düzeltme eki uygulanacak kaynak statik bir nesneyse, istek başarısız olur.
- Yama uygulanacak kaynak dinamik bir nesneyse:
fromözelliğini,pathtarafından belirtilen konuma kopyalar; ardındanfromözelliği üzerinde birremoveişlemi çalıştırır.
Aşağıdaki örnek düzeltme eki belgesi:
-
Orders[0].OrderNamedeğeriniCustomerNamekonumuna kopyalar. -
Orders[0].OrderName'ı null olarak ayarlar. -
Orders[1]öğesiniOrders[0]öğesinden önce taşır.
[
{
"op": "move",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "move",
"from": "/orders/1",
"path": "/orders/0"
}
]
Kopyalama işlemi
Bu işlem işlevsel olarak son move adım olmadan bir remove işlemle aynıdır.
Aşağıdaki örnek düzeltme eki belgesi:
-
Orders[0].OrderNamedeğeriniCustomerNamekonumuna kopyalar. -
Orders[1]öğesinin bir kopyasınıOrders[0]öğesinden önce ekler.
[
{
"op": "copy",
"from": "/orders/0/orderName",
"path": "/customerName"
},
{
"op": "copy",
"from": "/orders/1",
"path": "/orders/0"
}
]
Test işlemi
tarafından path belirtilen konumdaki değer, içinde valuesağlanan değerden farklıysa istek başarısız olur. Bu durumda düzeltme eki belgesindeki diğer tüm işlemler başarılı olsa bile PATCH isteğinin tamamı başarısız olur.
İşlem test genellikle eşzamanlılık çakışması olduğunda güncelleştirme yapılmasını önlemek için kullanılır.
Aşağıdaki örnek düzeltme eki belgesinin ilk değeri CustomerName "John" ise hiçbir etkisi yoktur, çünkü test başarısız olur:
[
{
"op": "test",
"path": "/customerName",
"value": "Nancy"
},
{
"op": "add",
"path": "/customerName",
"value": "Barry"
}
]
Kodu alın
Örnek kodu görüntüleyin veya indirme. (Nasıl indirilir).
Örneği test etmek için uygulamayı çalıştırın ve aşağıdaki ayarlarla HTTP istekleri gönderin:
- URL:
http://localhost:{port}/jsonpatch/jsonpatchwithmodelstate - HTTP yöntemi:
PATCH - Üstbilgi:
Content-Type: application/json-patch+json - Gövde: JSON proje klasöründeki JSON düzeltme eki belge örneklerinden birini kopyalayıp yapıştırın.
ASP.NET Core