Skip to content

Commit 06c3011

Browse files
authored
Merge pull request #35454 from dotnet/main
Merge to Live
2 parents 2418e1c + fbed1d3 commit 06c3011

File tree

11 files changed

+284
-3
lines changed

11 files changed

+284
-3
lines changed

aspnetcore/blazor/call-web-api.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,35 @@ Laid out with indentation, spacing, and unescaped quotes, the unencoded PATCH do
676676

677677
To simplify the creation of PATCH documents in the app issuing PATCH requests, an app can use .NET JSON PATCH support, as the following guidance demonstrates.
678678

679+
:::moniker-end
680+
681+
:::moniker range=">= aspnetcore-10.0"
682+
683+
<!-- UPDATE 10.0 - API doc cross-link -->
684+
685+
Install the [`Microsoft.AspNetCore.JsonPatch.SystemTextJson`](https://www.nuget.org/packages/Microsoft.AspNetCore.JsonPatch.SystemTextJson) NuGet package and use the API features of the package to compose a `JsonPatchDocument` for a PATCH request.
686+
687+
[!INCLUDE[](~/includes/package-reference.md)]
688+
689+
Add `@using` directives for the <xref:System.Text.Json?displayProperty=fullName>, <xref:System.Text.Json.Serialization?displayProperty=fullName>, and `Microsoft.AspNetCore.JsonPatch.SystemTextJson` <!-- <xref:Microsoft.AspNetCore.JsonPatch.SystemTextJson?displayProperty=fullName> --> namespaces to the top of the Razor component:
690+
691+
```razor
692+
@using System.Text.Json
693+
@using System.Text.Json.Serialization
694+
@using Microsoft.AspNetCore.JsonPatch.SystemTextJson
695+
```
696+
697+
Compose the `JsonPatchDocument` for a `TodoItem` with `IsComplete` set to `true` using the `JsonPatchDocument.Replace` method:
698+
699+
```csharp
700+
var patchDocument = new JsonPatchDocument<TodoItem>()
701+
.Replace(p => p.IsComplete, true);
702+
```
703+
704+
:::moniker-end
705+
706+
:::moniker range=">= aspnetcore-7.0 < aspnetcore-10.0"
707+
679708
Install the [`Microsoft.AspNetCore.JsonPatch`](https://www.nuget.org/packages/Microsoft.AspNetCore.JsonPatch) NuGet package and use the API features of the package to compose a <xref:Microsoft.AspNetCore.JsonPatch.JsonPatchDocument> for a PATCH request.
680709

681710
[!INCLUDE[](~/includes/package-reference.md)]
@@ -695,6 +724,10 @@ var patchDocument = new JsonPatchDocument<TodoItem>()
695724
.Replace(p => p.IsComplete, true);
696725
```
697726

727+
:::moniker-end
728+
729+
:::moniker range=">= aspnetcore-7.0"
730+
698731
Pass the document's operations (`patchDocument.Operations`) to the <xref:System.Net.Http.Json.HttpClientJsonExtensions.PatchAsJsonAsync%2A> call:
699732

700733
```csharp
@@ -716,6 +749,24 @@ Add <xref:System.Text.Json.JsonSerializerOptions.WriteIndented?displayProperty=n
716749

717750
Follow the guidance in the <xref:web-api/jsonpatch> article to add a PATCH controller action to the web API. Alternatively, PATCH request processing can be implemented as a [Minimal API](xref:fundamentals/minimal-apis) with the following steps.
718751

752+
:::moniker-end
753+
754+
:::moniker range=">= aspnetcore-10.0"
755+
756+
<!-- UPDATE 10.0 - API doc cross-link -->
757+
758+
Add a package reference for the [`Microsoft.AspNetCore.JsonPatch.SystemTextJson`](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.NewtonsoftJson) NuGet package to the web API app.
759+
760+
In the `Program` file add an `@using` directive for the `Microsoft.AspNetCore.JsonPatch.SystemTextJson` <!-- <xref:Microsoft.AspNetCore.JsonPatch.SystemTextJson?displayProperty=fullName> --> namespace:
761+
762+
```csharp
763+
using Microsoft.AspNetCore.JsonPatch.SystemTextJson;
764+
```
765+
766+
:::moniker-end
767+
768+
:::moniker range=">= aspnetcore-7.0 < aspnetcore-10.0"
769+
719770
Add a package reference for the [`Microsoft.AspNetCore.Mvc.NewtonsoftJson`](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.NewtonsoftJson) NuGet package to the web API app.
720771

721772
> [!NOTE]
@@ -727,6 +778,10 @@ In the `Program` file add an `@using` directive for the <xref:Microsoft.AspNetCo
727778
using Microsoft.AspNetCore.JsonPatch;
728779
```
729780

781+
:::moniker-end
782+
783+
:::moniker range=">= aspnetcore-7.0"
784+
730785
Provide the endpoint to the request processing pipeline of the web API:
731786

732787
```csharp
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
## Support for IOpenApiDocumentProvider in the DI container.
1+
### Support for IOpenApiDocumentProvider in the DI container.
22

33
ASP.NET Core in .NET 10 supports [IOpenApiDocumentProvider](https://source.dot.net/#Microsoft.AspNetCore.OpenApi/Services/IOpenApiDocumentProvider.cs) in the dependency injection (DI) container. Developers can inject `IOpenApiDocumentProvider` into their apps and use it to access the OpenAPI document. This approach is useful for accessing OpenAPI documents outside the context of HTTP requests, such as in background services or custom middleware.
44

5-
Previously, running application startup logic without launching an HTTP server could be done by using `HostFactoryResolver` with a no-op `IServer` implementation. The new feature simplifies this process by providing a streamlined API inspired by Aspire's <xref:Aspire.Hosting.Publishing.IDistributedApplicationPublisher>, which is part of Aspire's framework for distributed application hosting and publishing. For more information, see [Aspire Documentation](https://aspire.example.com/docs/distributed-application-publisher).
6-
5+
Previously, running application startup logic without launching an HTTP server could be done by using `HostFactoryResolver` with a no-op `IServer` implementation. The new feature simplifies this process by providing a streamlined API inspired by Aspire's <xref:Aspire.Hosting.Publishing.IDistributedApplicationPublisher>, which is part of Aspire's framework for distributed application hosting and publishing. For more information, see [Aspire Documentation](https://aspire.example.com/docs/distributed-application-publisher) and [dotnet/aspnetcore #61463](https://github.com/dotnet/aspnetcore/pull/61463).
76

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using JsonPatchSample.Models;
2+
using Microsoft.AspNetCore.JsonPatch;
3+
using Microsoft.AspNetCore.Mvc;
4+
using System.Collections.Generic;
5+
using System.Dynamic;
6+
7+
namespace JsonPatchSample.Controllers;
8+
9+
[Route("jsonpatch/[action]")]
10+
[ApiController]
11+
public class HomeController : ControllerBase
12+
{
13+
// <snippet_PatchAction>
14+
[HttpPatch]
15+
public IActionResult JsonPatchWithModelState(
16+
[FromBody] JsonPatchDocument<Customer> patchDoc)
17+
{
18+
if (patchDoc != null)
19+
{
20+
var customer = CreateCustomer();
21+
22+
patchDoc.ApplyTo(customer, ModelState);
23+
24+
if (!ModelState.IsValid)
25+
{
26+
return BadRequest(ModelState);
27+
}
28+
29+
return new ObjectResult(customer);
30+
}
31+
else
32+
{
33+
return BadRequest(ModelState);
34+
}
35+
}
36+
// </snippet_PatchAction>
37+
38+
[HttpPatch]
39+
public IActionResult JsonPatchWithModelStateAndPrefix(
40+
[FromBody] JsonPatchDocument<Customer> patchDoc,
41+
string prefix)
42+
{
43+
var customer = CreateCustomer();
44+
45+
patchDoc.ApplyTo(customer, ModelState, prefix);
46+
47+
if (!ModelState.IsValid)
48+
{
49+
return BadRequest(ModelState);
50+
}
51+
52+
return new ObjectResult(customer);
53+
}
54+
55+
[HttpPatch]
56+
public IActionResult JsonPatchWithoutModelState([FromBody] JsonPatchDocument<Customer> patchDoc)
57+
{
58+
var customer = CreateCustomer();
59+
60+
patchDoc.ApplyTo(customer);
61+
62+
return new ObjectResult(customer);
63+
}
64+
65+
[HttpPatch]
66+
public IActionResult JsonPatchForProduct([FromBody] JsonPatchDocument<Product> patchDoc)
67+
{
68+
var product = new Product();
69+
70+
patchDoc.ApplyTo(product);
71+
72+
return new ObjectResult(product);
73+
}
74+
75+
// <snippet_Dynamic>
76+
[HttpPatch]
77+
public IActionResult JsonPatchForDynamic([FromBody]JsonPatchDocument patch)
78+
{
79+
dynamic obj = new ExpandoObject();
80+
patch.ApplyTo(obj);
81+
82+
return Ok(obj);
83+
}
84+
// </snippet_Dynamic>
85+
86+
private Customer CreateCustomer()
87+
{
88+
return new Customer
89+
{
90+
CustomerName = "John",
91+
Orders = new List<Order>()
92+
{
93+
new Order
94+
{
95+
OrderName = "Order0"
96+
},
97+
new Order
98+
{
99+
OrderName = "Order1"
100+
}
101+
}
102+
};
103+
}
104+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<Folder Include="Controllers\" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.2" />
15+
</ItemGroup>
16+
17+
</Project>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Newtonsoft.Json;
2+
3+
namespace JsonPatchSample.Models
4+
{
5+
public class Category
6+
{
7+
public string CategoryName { get; set; }
8+
}
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace JsonPatchSample.Models;
2+
3+
public class Customer
4+
{
5+
public string? CustomerName { get; set; }
6+
public List<Order>? Orders { get; set; }
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace JsonPatchSample.Models;
2+
3+
public class Order
4+
{
5+
public string OrderName { get; set; }
6+
public string OrderType { get; set; }
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace JsonPatchSample.Models
2+
{
3+
public class Product
4+
{
5+
public string ProductName { get; set; }
6+
public Category ProductCategory { get; set; }
7+
}
8+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Mvc.Formatters;
3+
using Microsoft.Extensions.Options;
4+
5+
namespace JsonPatchSample;
6+
7+
public static class MyJPIF
8+
{
9+
public static NewtonsoftJsonPatchInputFormatter GetJsonPatchInputFormatter()
10+
{
11+
var builder = new ServiceCollection()
12+
.AddLogging()
13+
.AddMvc()
14+
.AddNewtonsoftJson()
15+
.Services.BuildServiceProvider();
16+
17+
return builder
18+
.GetRequiredService<IOptions<MvcOptions>>()
19+
.Value
20+
.InputFormatters
21+
.OfType<NewtonsoftJsonPatchInputFormatter>()
22+
.First();
23+
}
24+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#define BOTH // FIRST BOTH
2+
#if NEVER
3+
#elif FIRST
4+
// <snippet1>
5+
var builder = WebApplication.CreateBuilder(args);
6+
7+
builder.Services.AddControllers()
8+
.AddNewtonsoftJson();
9+
10+
var app = builder.Build();
11+
12+
app.UseHttpsRedirection();
13+
14+
app.UseAuthorization();
15+
16+
app.MapControllers();
17+
18+
app.Run();
19+
// </snippet1>
20+
#elif BOTH
21+
// <snippet_both>
22+
using JsonPatchSample;
23+
using Microsoft.AspNetCore.Mvc.Formatters;
24+
25+
var builder = WebApplication.CreateBuilder(args);
26+
27+
builder.Services.AddControllers(options =>
28+
{
29+
options.InputFormatters.Insert(0, MyJPIF.GetJsonPatchInputFormatter());
30+
});
31+
32+
var app = builder.Build();
33+
34+
app.UseHttpsRedirection();
35+
36+
app.UseAuthorization();
37+
38+
app.MapControllers();
39+
40+
app.Run();
41+
// </snippet_both>
42+
#endif

0 commit comments

Comments
 (0)