Skip to content

Commit de4f772

Browse files
authored
PATCH and other sample updates (dotnet#231)
1 parent 508c92f commit de4f772

File tree

10 files changed

+155
-7
lines changed

10 files changed

+155
-7
lines changed

8.0/BlazorWebAppCallWebApi/Backend/Backend.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
<ItemGroup>
1111
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" />
12+
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.0" />
1213
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0" />
1314
<PackageReference Include="NSwag.AspNetCore" Version="14.0.3" />
1415
</ItemGroup>

8.0/BlazorWebAppCallWebApi/Backend/Backend.http

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@Backend_HostAddress = https://localhost:7211
1+
@Backend_HostAddress = https://localhost:7212
22

33
GET {{Backend_HostAddress}}/todoitems/
44
Accept: application/json
@@ -10,10 +10,27 @@ Accept: application/json
1010

1111
###
1212

13+
GET {{Backend_HostAddress}}/todoitems/incomplete
14+
Accept: application/json
15+
16+
###
17+
1318
GET {{Backend_HostAddress}}/todoitems/2
1419

1520
###
1621

22+
PATCH {{Backend_HostAddress}}/todoitems/2
23+
Content-Type: application/json
24+
25+
{
26+
"operationType": 2,
27+
"path": "/IsComplete",
28+
"op": "replace",
29+
"value": true
30+
}
31+
32+
###
33+
1734
Post {{Backend_HostAddress}}/todoitems
1835
Content-Type: application/json
1936

8.0/BlazorWebAppCallWebApi/Backend/Program.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Microsoft.AspNetCore.JsonPatch;
12
using Microsoft.EntityFrameworkCore;
23
using Backend;
34
using Backend.Models;
@@ -45,10 +46,12 @@
4546

4647
todoItems.MapGet("/", GetAllTodos);
4748
todoItems.MapGet("/complete", GetCompleteTodos);
49+
todoItems.MapGet("/incomplete", GetIncompleteTodos);
4850
todoItems.MapGet("/{id}", GetTodo);
4951
todoItems.MapPost("/", CreateTodo);
5052
todoItems.MapPut("/{id}", UpdateTodo);
5153
todoItems.MapDelete("/{id}", DeleteTodo);
54+
todoItems.MapPatch("/{id}", PatchTodo);
5255

5356
app.Run();
5457

@@ -62,6 +65,11 @@ static async Task<IResult> GetCompleteTodos(TodoContext db)
6265
return TypedResults.Ok(await db.TodoItems.Where(t => t.IsComplete).ToListAsync());
6366
}
6467

68+
static async Task<IResult> GetIncompleteTodos(TodoContext db)
69+
{
70+
return TypedResults.Ok(await db.TodoItems.Where(t => !t.IsComplete).ToListAsync());
71+
}
72+
6573
static async Task<IResult> GetTodo(long id, TodoContext db)
6674
{
6775
return await db.TodoItems.FindAsync(id) is TodoItem todo ? TypedResults.Ok(todo) : TypedResults.NotFound();
@@ -104,3 +112,17 @@ static async Task<IResult> DeleteTodo(long id, TodoContext db)
104112

105113
return TypedResults.NotFound();
106114
}
115+
116+
static async Task<IResult> PatchTodo(long id, TodoContext db)
117+
{
118+
if (await db.TodoItems.FindAsync(id) is TodoItem todo)
119+
{
120+
var patchDocument = new JsonPatchDocument<TodoItem>().Replace(p => p.IsComplete, true);
121+
patchDocument.ApplyTo(todo);
122+
await db.SaveChangesAsync();
123+
124+
return TypedResults.Ok(todo);
125+
}
126+
127+
return TypedResults.NoContent();
128+
}

8.0/BlazorWebAppCallWebApi/BlazorApp/BlazorApp.Client/BlazorApp.Client.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.2" />
12+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
13+
<PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="8.0.0" />
1314
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
1415
</ItemGroup>
1516

8.0/BlazorWebAppCallWebApi/BlazorApp/BlazorApp.Client/Layout/NavMenu.razor

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@
5353
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Todo Typed Client
5454
</NavLink>
5555
</div>
56+
<div class="nav-item px-3">
57+
<NavLink class="nav-link" href="call-todo-web-api-csr-patch">
58+
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Todo List (PATCH)
59+
</NavLink>
60+
</div>
5661
</nav>
5762
</div>
5863

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
@page "/call-todo-web-api-csr-patch"
2+
@rendermode InteractiveWebAssembly
3+
@using System.Text.Json
4+
@using System.Text.Json.Serialization
5+
@using Microsoft.AspNetCore.JsonPatch
6+
@using BlazorApp.Client.Models
7+
@implements IDisposable
8+
@inject PersistentComponentState ApplicationState
9+
@inject IHttpClientFactory ClientFactory
10+
11+
<PageTitle>Call Todo web API (CSR, PATCH)</PageTitle>
12+
13+
<h1>Call Todo web API Example (CSR, PATCH)</h1>
14+
15+
@if (todoItems == null)
16+
{
17+
<p>No Todo Items found.</p>
18+
}
19+
else
20+
{
21+
<ul>
22+
@foreach (var item in todoItems)
23+
{
24+
<li>
25+
@item.Name
26+
<button class="btn btn-secondary" @onclick="_ => UpdateItemRaw(item.Id)">
27+
Mark 'Complete' raw body
28+
</button>
29+
<button class="btn btn-primary" @onclick="_ => UpdateItem(item.Id)">
30+
Mark 'Complete' PATCH doc
31+
</button>
32+
</li>
33+
}
34+
</ul>
35+
}
36+
37+
@code {
38+
JsonPatchDocument<TodoItem> patchDocument = new JsonPatchDocument<TodoItem>().Replace(p => p.IsComplete, true);
39+
private TodoItem[]? todoItems;
40+
private PersistingComponentStateSubscription persistingSubscription;
41+
private HttpClient? client;
42+
43+
protected override async Task OnInitializedAsync()
44+
{
45+
client = ClientFactory.CreateClient("WebAPI");
46+
persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
47+
48+
if (!ApplicationState.TryTakeFromJson<TodoItem[]>(nameof(todoItems), out var restoredData))
49+
{
50+
await GetTodoItems();
51+
}
52+
else
53+
{
54+
todoItems = restoredData!;
55+
}
56+
}
57+
58+
private async Task GetTodoItems()
59+
{
60+
if (client is not null)
61+
{
62+
todoItems = await client.GetFromJsonAsync<TodoItem[]>("todoitems/incomplete") ?? [];
63+
}
64+
}
65+
66+
private Task PersistData()
67+
{
68+
ApplicationState.PersistAsJson(nameof(todoItems), todoItems);
69+
70+
return Task.CompletedTask;
71+
}
72+
73+
private async Task UpdateItemRaw(long id)
74+
{
75+
if (client is not null)
76+
{
77+
await client.PatchAsJsonAsync(
78+
$"todoitems/{id}",
79+
"[{\"operationType\":2,\"path\":\"/IsComplete\",\"op\":\"replace\",\"value\":true}]");
80+
await GetTodoItems();
81+
}
82+
}
83+
84+
private async Task UpdateItem(long id)
85+
{
86+
if (client is not null)
87+
{
88+
// Set WriteIndented to 'true' to format JSON during debugging
89+
await client.PatchAsJsonAsync(
90+
$"todoitems/{id}",
91+
patchDocument.Operations,
92+
new JsonSerializerOptions()
93+
{
94+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
95+
WriteIndented = false
96+
});
97+
await GetTodoItems();
98+
}
99+
}
100+
101+
void IDisposable.Dispose() => persistingSubscription.Dispose();
102+
}

8.0/BlazorWebAppCallWebApi/BlazorApp/BlazorApp.Client/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
builder.Services.AddHttpClient("WebAPI", client => client.BaseAddress = new Uri(builder.Configuration["BackendUrl"] ?? "https://localhost:5002"));
1616

1717
// Register the app's typed HttpClient for the typed client component example
18-
builder.Services.AddHttpClient<TodoHttpClient>();
18+
builder.Services.AddHttpClient<TodoHttpClient>(client => client.BaseAddress = new Uri(builder.Configuration["BackendUrl"] ?? "https://localhost:5002"));
1919

2020
await builder.Build().RunAsync();

8.0/BlazorWebAppCallWebApi/BlazorApp/BlazorApp.Client/TodoHttpClient.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44
namespace BlazorApp.Client;
55

6-
public class TodoHttpClient(IConfiguration config, HttpClient http)
6+
public class TodoHttpClient(HttpClient client)
77
{
88
public async Task<TodoItem[]> GetTodoItemsAsync()
99
{
10-
return await http.GetFromJsonAsync<TodoItem[]>($"{config.GetValue<string>("BackendUrl")}/todoitems") ?? [];
10+
return await client.GetFromJsonAsync<TodoItem[]>("todoitems") ?? [];
1111
}
1212
}

8.0/BlazorWebAppCallWebApi/BlazorApp/BlazorApp/BlazorApp.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<ItemGroup>
1010
<ProjectReference Include="..\BlazorApp.Client\BlazorApp.Client.csproj" />
11-
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.2" />
11+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.0" />
1212
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" />
1313
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0" />
1414
<PackageReference Include="NSwag.AspNetCore" Version="14.0.3" />

8.0/BlazorWebAppCallWebApi/BlazorApp/BlazorApp/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
// For prerendering purposes, register the client app's typed HttpClient
2828
// for the app's typed client component example.
29-
builder.Services.AddHttpClient<TodoHttpClient>();
29+
builder.Services.AddHttpClient<TodoHttpClient>(client => client.BaseAddress = new Uri(builder.Configuration["BackendUrl"] ?? "https://localhost:5002"));
3030

3131
// Add Todo service for components adopting SSR
3232
builder.Services.AddScoped<IMovieService, ServerMovieService>();

0 commit comments

Comments
 (0)