PunchKano begins diphtheria immunisation in five Kano LGsRTP DesportoFrancisco Cabral na final de pares em HangzhouESPN DeportesGrecia derrotó a Alemania por primera vez en la historia y golpeó a Klopp en su debut ante su públicoThe Jerusalem PostIsrair awaits final approval for Tokyo, Miami flights, adds new European destinations for 2027Daily MaverickWe worried AI would make things up, we should also worry when it doesn’tInquirerRains to continue in Visayas, Mindanao due to ITCZ until Sept. 30Bollywood HungamaVinod Kapri's Pyre to release in theaters on October 23, 2026BlickNächstes Amt abgelegt: Jens Spahn zieht sich aus Haushaltsausschuss zurückRapplerPhilippines should fix tax gaps and procurement, not raise tax rates – WBSportstarIndia in Athletics LIVE Updates, Asian Games 2026: Vithya Ramraj breaks National Record to win 400m hurdles bronze; Javelin throw final at 4:45 PM ISTIl Fatto QuotidianoMorto Stefano Milani, il tifoso del Milan diventato famoso su X. Da Bertolucci a Valenti: “Ha lottato come nessuno, mai un passo indietro”7sur7“Pourquoi je perds toujours?”: quand André Agassi taquine Alexander Zverev
The Daily Newsstand · Free, Always
Monday, September 28, 2026

Neu in .NET 10.0 [42]: JSON Patch in ASP.NET-Core-WebAPIs

Translate

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.

Der Dotnet-Doktor – Holger Schwichtenberg

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.

Screenshot

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).

View the original on heise online →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.