Die neue JSON-Patch-Implementierung in .NET 10.0 lässt sich auch in WebAPIs verwenden.
Seit .NET 10.0 ist es möglich, die JSON-Patch-Implementierung in WebAPIs zu verwenden. Das folgende Beispiel zeigt, wie man das neue NuGet-Paket Microsoft.AspNetCore.JsonPatch.SystemTextJson in einer ASP.NET-Core-10.0-basierten WebAPI anwendet, um ein JSON-Patch-Dokument zu verarbeiten.
Dr. Holger Schwichtenberg ist technischer Leiter des Expertennetzwerks www.IT-Visions.de, das mit 53 renommierten Experten zahlreiche mittlere und große Unternehmen durch Beratungen und Schulungen sowie bei der Softwareentwicklung unterstützt. Durch seine Auftritte auf zahlreichen nationalen und internationalen Fachkonferenzen sowie mehr als 90 Fachbücher und mehr als 1500 Fachartikel gehört Holger Schwichtenberg zu den bekanntesten Experten für .NET und Webtechniken in Deutschland.
Die Datenklassen sind dieselben wie in dem Beispiel zum Beitrag „JSON Patch“ in dieser Blogserie: Person, Address und PhoneNumber.
Die WebAPI-Aktionsmethode besitzt einen Parameter vom Typ JsonPatchDocument<Person>. Das JSON-Patch-Dokument wird im Body des HTTP-Aufrufs erwartet.
(Bild: King / stock. adobe.com)
Das ist neu in .NET 11.0: Dr. Holger Schwichtenberg und weitere Experten präsentieren am 17. November 2026 auf der Online-Konferenz betterCode() .NET 11.0 die Änderungen für Entwicklerinnen und Entwickler. Tickets zum Frühbucherpreis sind bis 20.10. im Online-Shop verfügbar.
Leider funktioniert das neue JSON-Patch-Paket nicht in Verbindung mit dem NativeAOT-Compiler, sondern nur mit dem Just-in-Time-Compiler.
Folgender Code zeigt JSON Patch mit Microsoft.AspNetCore.JsonPatch.SystemTextJson:
using System;
using System.Formats.Asn1;
using System.Net.ServerSentEvents;
using System.Runtime.CompilerServices;
using ITVisions;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.JsonPatch.SystemTextJson;
using Microsoft.AspNetCore.Mvc;
namespace NET10_WebAPIController.Controllers;
/// <summary>
/// Personendaten holen und aktualisieren mit einem JSON-Patch-Dokument
/// </summary>
[ApiController]
[Route("[controller]")]
public class PersonController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
public PersonController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
/// <summary>
/// Diese WebAPI-Operation liefert die Daten zu einer Person anhand der ID
/// </summary>
/// <remarks>Es wird aktuell immer die gleiche Person geliefert ;-(</remarks>
/// <param name="id">ID der Person</param>
/// <returns>Person-Objekt mit Adresse</returns>
[HttpGet]
[Route("/Person_OhneTypedResult/{id}")]
public async Task<Person> Get1(int id = 0)
{
var person = await new PersonManager().GetPersonByIdAsync(id);
return person;
}
/// <summary>
/// Diese WebAPI-Operation liefert die Daten zu einer Person anhand der ID
/// </summary>
/// <remarks>Es wird aktuell immer die gleiche Person geliefert ;-(</remarks>
/// <param name="id">ID der Person</param>
/// <returns>Person-Objekt mit Adresse</returns>
[HttpGet]
[Route("/Person_MitTypedResult/{id}")]
[ProducesResponseType<IEnumerable<WeatherForecast>>(StatusCodes.Status200OK, Description = "Person-Objekt mit Adresse (aus [ProducesResponseType])")]
[ProducesResponseType<ValidationProblem>(StatusCodes.Status400BadRequest, Description = "Fehlerhafte Anfrage / ID muss größer als 0 sein!")]
[ProducesResponseType<ValidationProblem>(StatusCodes.Status404NotFound, Description = "Person nicht gefunden")]
public async Task<Results<Ok<Person>, ValidationProblem, NotFound<ProblemDetails>>> Get_MitTypedResult(int id = 0)
{
if (id <= 0)
{
return TypedResults.ValidationProblem(new Dictionary<string, string[]> { { "id", new[] { "ID muss größer als 0 sein!" } } });
}
var person = await new PersonManager().GetPersonByIdAsync(id);
if (person == null)
{
return TypedResults.NotFound(new ProblemDetails { Title = "Person not found", Detail = $"Person mit ID {id} nicht gefunden!" });
}
return TypedResults.Ok(person);
}
// PATCH https://localhost:7022/person/123
[HttpPatch]
[Route("{id}")]
public async Task<Results<Ok<Person>, ValidationProblem, NotFound<ProblemDetails>>> UpdatePerson(int id, JsonPatchDocument<Person> patchDoc = null)
{
var person = await new PersonManager().GetPersonByIdAsync(id);
if (person == null)
{
return TypedResults.NotFound(new ProblemDetails { Title = "Person not found", Detail = $"No person found with ID {id}" });
}
if (patchDoc != null)
{
Dictionary<string, string[]> errors = new Dictionary<string, string[]>();
// JSON-Patch-Dokument anwenden auf das Person-Objekt
int errorCount = 0;
patchDoc!.ApplyTo(person, patchError =>
{
errors.Add(patchError.AffectedObject.GetType().Name + "#" + ++errorCount, new[] { patchError.ErrorMessage });
});
if (errors.Count > 0)
{
return TypedResults.ValidationProblem(errors);
}
}
return TypedResults.Ok(person);
}
}
Folgender Beispielcode simuliert die vom obigen Controller genutzte Geschäftslogik:
public class PersonManager
{
public async Task<Person?> GetPersonByIdAsync(int id)
{
// Originalobjekt
var person = new Person
{
FirstName = "Holger",
LastName = "Schwichtenberg",
PrivateEmail = "buero@IT-Visions.de",
PrivateWebsite = "www.dotnet-doktor.de",
CompanyWebsite = "www.IT-Visions.de",
PhoneNumbers = [new PhoneNumber() { Number = "0201 649590-0", Type = PhoneNumberType.Work }],
Address = new Address
{
Street = "Fahrenberg 40b",
City = "Essen",
State = "NRW"
}
};
return await Task.FromResult(person);
}
}
Da man einen PATCH-Aufruf nicht einfach über die Adresszeile eines Webbrowsers auslösen kann, verwendet man zum Testen die HTTP-Tests in Visual Studio (.http-Dateien) oder ein externes Werkzeug wie Fiddler oder Postman. Das JSON-Patch-Dokument übergibt man via HTTP-Body.
Aufruf einer ASP.NET-Core-basierten WebAPI, die ein JSON-Patch-Dokument erwartet und ein geändertes Objekt liefert, in einer .http-Datei innerhalb von Visual Studio (Abb. 1).
Aufruf einer ASP.NET-Core-basierten WebAPI, die ein JSON-Patch-Dokument erwartet und ein geändertes Objekt liefert, in Postman (Abb. 2).
(rme)
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | AMD Posts GCC Compiler Patches For AVX10V1AUX ISA Support | 0 | 11.85 | 24-09-2026 |
| 2 | Microsoft shares new Edge tools to fill key performance gaps to improve slow web apps | 0 | 10.76 | 27-09-2026 |
| 3 | Telekom: Mehr Sicherheit für diese Speedport-Router | 0 | 19.98 | 25-09-2026 |
| 4 | Firefox 157 Now Available With Visual Refresh, WebRTC Hardware AV1 Decode | 0 | 19.3 | 28-09-2026 |
| 5 | Drupal CMS 2.2.0 vereinfacht mehrsprachige Websites | 0 | 13.19 | 28-09-2026 |
| 6 | Microsoft beerdigt „Copilot+“ | 0 | 17.78 | 25-09-2026 |
| 7 | New Patch Series Working Toward DRBD 9 Support In The Linux Kernel | 0 | 7.9 | 27-09-2026 |
| 8 | iTProtect выпустил новую версию iTProtect Scout | 0 | 7.79 | 28-09-2026 |
| 9 | iTProtect выпустил новую версию iTProtect Scout | 0 | 7.79 | 28-09-2026 |