Skip to content

Commit e93c900

Browse files
committed
Update 09-progressive-web-app
1 parent 522d3c1 commit e93c900

31 files changed

+388
-234
lines changed

docs/09-progressive-web-app.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,21 @@ You'll then need to define `RequestNotificationSubscriptionAsync`. Add this else
120120
```cs
121121
async Task RequestNotificationSubscriptionAsync()
122122
{
123-
var subscription = await JSRuntime.InvokeAsync<NotificationSubscription>("blazorPushNotifications.requestSubscription");
124-
if (subscription != null)
123+
var tokenResult = await TokenProvider.RequestAccessToken();
124+
if (tokenResult.TryGetToken(out var accessToken))
125125
{
126-
await HttpClient.PutJsonAsync<object>("notifications/subscribe", subscription);
126+
var subscription = await JSRuntime.InvokeAsync<NotificationSubscription>("blazorPushNotifications.requestSubscription");
127+
if (subscription != null)
128+
{
129+
var request = new HttpRequestMessage(HttpMethod.Put, "notifications/subscribe");
130+
request.Content = JsonContent.Create(subscription);
131+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Value);
132+
await HttpClient.SendAsync(request);
133+
}
134+
}
135+
else
136+
{
137+
NavigationManager.NavigateTo(tokenResult.RedirectUrl);
127138
}
128139
}
129140
```

save-points/09-progressive-web-app/BlazingPizza.Client/App.razor

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
<Found>
44
<AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)">
55
<NotAuthorized>
6-
<div class="main">
7-
<h2>You're signed out</h2>
8-
<p>To continue, please sign in.</p>
9-
<a class="btn btn-danger" href="user/signin">Sign in</a>
10-
</div>
6+
<RedirectToLogin />
117
</NotAuthorized>
128
<Authorizing>
139
<div class="main">Please wait...</div>
@@ -16,7 +12,7 @@
1612
</Found>
1713
<NotFound>
1814
<LayoutView Layout="typeof(MainLayout)">
19-
<div class="main">Page not found</div>
15+
<div class="main">Sorry, there's nothing at this address.</div>
2016
</LayoutView>
2117
</NotFound>
2218
</Router>

save-points/09-progressive-web-app/BlazingPizza.Client/BlazingPizza.Client.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
<ItemGroup>
1010
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="$(BlazorVersion)" />
1111
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="$(BlazorVersion)" PrivateAssets="all" />
12-
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="$(BlazorVersion)" />
13-
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="$(AspNetCoreVersion)" />
12+
<PackageReference Include="System.Net.Http.Json" Version="$(SystemNetHttpJsonVersion)" />
13+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="$(BlazorVersion)" />
1414
</ItemGroup>
1515

1616
<ItemGroup>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
@page "/authentication/{action}"
2+
@inject OrderState OrderState
3+
@inject NavigationManager NavigationManager
4+
5+
<RemoteAuthenticatorViewCore
6+
TAuthenticationState="PizzaAuthenticationState"
7+
AuthenticationState="RemoteAuthenticationState"
8+
OnLogInSucceeded="RestorePizza"
9+
Action="@Action" />
10+
11+
@code{
12+
[Parameter] public string Action { get; set; }
13+
14+
public PizzaAuthenticationState RemoteAuthenticationState { get; set; } = new PizzaAuthenticationState();
15+
16+
protected override void OnInitialized()
17+
{
18+
if (RemoteAuthenticationActions.IsAction(RemoteAuthenticationActions.LogIn, Action))
19+
{
20+
// Preserve the current order so that we don't loose it
21+
RemoteAuthenticationState.Order = OrderState.Order;
22+
}
23+
}
24+
25+
private void RestorePizza(PizzaAuthenticationState pizzaState)
26+
{
27+
if (pizzaState.Order != null)
28+
{
29+
OrderState.ReplaceOrder(pizzaState.Order);
30+
}
31+
}
32+
}
Lines changed: 51 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,80 @@
11
@page "/checkout"
2+
@attribute [Authorize]
23
@inject OrderState OrderState
34
@inject HttpClient HttpClient
45
@inject NavigationManager NavigationManager
6+
@inject IAccessTokenProvider TokenProvider
57
@inject IJSRuntime JSRuntime
68

79
<div class="main">
8-
<AuthorizeView Context="authContext">
9-
<NotAuthorized>
10-
<h2>Redirecting you...</h2>
11-
</NotAuthorized>
12-
<Authorized>
13-
<EditForm Model="OrderState.Order.DeliveryAddress" OnValidSubmit="PlaceOrder">
14-
<div class="checkout-cols">
15-
<div class="checkout-order-details">
16-
<h4>Review order</h4>
17-
<OrderReview Order="OrderState.Order" />
18-
</div>
10+
<EditForm Model="OrderState.Order.DeliveryAddress" OnValidSubmit="PlaceOrder">
11+
<div class="checkout-cols">
12+
<div class="checkout-order-details">
13+
<h4>Review order</h4>
14+
<OrderReview Order="OrderState.Order" />
15+
</div>
1916

20-
<div class="checkout-delivery-address">
21-
<h4>Deliver to...</h4>
22-
<AddressEditor Address="OrderState.Order.DeliveryAddress" />
23-
</div>
24-
</div>
17+
<div class="checkout-delivery-address">
18+
<h4>Deliver to...</h4>
19+
<AddressEditor Address="OrderState.Order.DeliveryAddress" />
20+
</div>
21+
</div>
2522

26-
<button type="submit" class="checkout-button btn btn-warning">
27-
Place order
28-
</button>
23+
<button type="submit" class="checkout-button btn btn-warning" disabled="@isSubmitting">
24+
Place order
25+
</button>
2926

30-
<DataAnnotationsValidator />
31-
</EditForm>
32-
</Authorized>
33-
</AuthorizeView>
27+
<DataAnnotationsValidator />
28+
</EditForm>
3429
</div>
3530

3631
@code {
37-
[CascadingParameter] public Task<AuthenticationState> AuthenticationStateTask { get; set; }
32+
bool isSubmitting;
3833

39-
protected override async Task OnInitializedAsync()
34+
protected override void OnInitialized()
4035
{
41-
var authState = await AuthenticationStateTask;
42-
if (!authState.User.Identity.IsAuthenticated)
43-
{
44-
// The server won't accept orders from unauthenticated users, so avoid
45-
// an error by making them log in at this point
46-
await LocalStorage.SetAsync(JSRuntime, "currentorder", OrderState.Order);
47-
NavigationManager.NavigateTo("user/signin?redirectUri=/checkout", true);
48-
}
36+
// In the background, ask if they want to be notified about order updates
37+
_ = RequestNotificationSubscriptionAsync();
38+
}
4939

50-
// Try to recover any temporary saved order
51-
if (!OrderState.Order.Pizzas.Any())
40+
async Task RequestNotificationSubscriptionAsync()
41+
{
42+
var tokenResult = await TokenProvider.RequestAccessToken();
43+
if (tokenResult.TryGetToken(out var accessToken))
5244
{
53-
var savedOrder = await LocalStorage.GetAsync<Order>(JSRuntime, "currentorder");
54-
if (savedOrder != null)
45+
var subscription = await JSRuntime.InvokeAsync<NotificationSubscription>("blazorPushNotifications.requestSubscription");
46+
if (subscription != null)
5547
{
56-
OrderState.ReplaceOrder(savedOrder);
57-
await LocalStorage.DeleteAsync(JSRuntime, "currentorder");
58-
}
59-
else
60-
{
61-
// There's nothing check out - go to home
62-
NavigationManager.NavigateTo("");
48+
var request = new HttpRequestMessage(HttpMethod.Put, "notifications/subscribe");
49+
request.Content = JsonContent.Create(subscription);
50+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Value);
51+
await HttpClient.SendAsync(request);
6352
}
6453
}
65-
66-
// In the background, ask if they want to be notified about order updates
67-
_ = RequestNotificationSubscriptionAsync();
54+
else
55+
{
56+
NavigationManager.NavigateTo(tokenResult.RedirectUrl);
57+
}
6858
}
6959

7060
async Task PlaceOrder()
7161
{
72-
var newOrderId = await HttpClient.PostJsonAsync<int>("orders", OrderState.Order);
73-
OrderState.ResetOrder();
74-
NavigationManager.NavigateTo($"myorders/{newOrderId}");
75-
}
62+
isSubmitting = true;
7663

77-
async Task RequestNotificationSubscriptionAsync()
78-
{
79-
var subscription = await JSRuntime.InvokeAsync<NotificationSubscription>("blazorPushNotifications.requestSubscription");
80-
if (subscription != null)
64+
var tokenResult = await TokenProvider.RequestAccessToken();
65+
if (tokenResult.TryGetToken(out var accessToken))
66+
{
67+
var request = new HttpRequestMessage(HttpMethod.Post, "orders");
68+
request.Content = JsonContent.Create(OrderState.Order);
69+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Value);
70+
var response = await HttpClient.SendAsync(request);
71+
var newOrderId = await response.Content.ReadFromJsonAsync<int>();
72+
OrderState.ResetOrder();
73+
NavigationManager.NavigateTo($"myorders/{newOrderId}");
74+
}
75+
else
8176
{
82-
await HttpClient.PutJsonAsync<object>("notifications/subscribe", subscription);
77+
NavigationManager.NavigateTo(tokenResult.RedirectUrl);
8378
}
8479
}
8580
}

save-points/09-progressive-web-app/BlazingPizza.Client/Pages/Index.razor

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

6262
protected override async Task OnInitializedAsync()
6363
{
64-
specials = await HttpClient.GetJsonAsync<List<PizzaSpecial>>("specials");
64+
specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>("specials");
6565
}
6666

6767
async Task RemovePizza(Pizza configuredPizza)

save-points/09-progressive-web-app/BlazingPizza.Client/Pages/MyOrders.razor

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
@page "/myorders"
22
@attribute [Authorize]
33
@inject HttpClient HttpClient
4+
@inject NavigationManager NavigationManager
5+
@inject IAccessTokenProvider TokenProvider
46

57
<div class="main">
68
<TemplatedList Loader="@LoadOrders" ListGroupClass="orders-list">
@@ -32,6 +34,19 @@
3234
@code {
3335
async Task<List<OrderWithStatus>> LoadOrders()
3436
{
35-
return await HttpClient.GetJsonAsync<List<OrderWithStatus>>("orders");
37+
var ordersWithStatus = new List<OrderWithStatus>();
38+
var tokenResult = await TokenProvider.RequestAccessToken();
39+
if (tokenResult.TryGetToken(out var accessToken))
40+
{
41+
var request = new HttpRequestMessage(HttpMethod.Get, "orders");
42+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Value);
43+
var response = await HttpClient.SendAsync(request);
44+
ordersWithStatus = await response.Content.ReadFromJsonAsync<List<OrderWithStatus>>();
45+
}
46+
else
47+
{
48+
NavigationManager.NavigateTo(tokenResult.RedirectUrl);
49+
}
50+
return ordersWithStatus;
3651
}
3752
}

save-points/09-progressive-web-app/BlazingPizza.Client/Pages/OrderDetails.razor

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
@attribute [Authorize]
33
@using System.Threading
44
@inject HttpClient HttpClient
5+
@inject NavigationManager NavigationManager
6+
@inject IAccessTokenProvider TokenProvider
57
@implements IDisposable
68

79
<div class="main">
@@ -55,24 +57,35 @@
5557

5658
private async void PollForUpdates()
5759
{
58-
pollingCancellationToken = new CancellationTokenSource();
59-
while (!pollingCancellationToken.IsCancellationRequested)
60+
var tokenResult = await TokenProvider.RequestAccessToken();
61+
if (tokenResult.TryGetToken(out var accessToken))
6062
{
61-
try
63+
pollingCancellationToken = new CancellationTokenSource();
64+
while (!pollingCancellationToken.IsCancellationRequested)
6265
{
63-
invalidOrder = false;
64-
orderWithStatus = await HttpClient.GetJsonAsync<OrderWithStatus>($"orders/{OrderId}");
65-
}
66-
catch (Exception ex)
67-
{
68-
invalidOrder = true;
69-
pollingCancellationToken.Cancel();
70-
Console.Error.WriteLine(ex);
71-
}
66+
try
67+
{
68+
invalidOrder = false;
69+
var request = new HttpRequestMessage(HttpMethod.Get, $"orders/{OrderId}");
70+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Value);
71+
var response = await HttpClient.SendAsync(request);
72+
orderWithStatus = await response.Content.ReadFromJsonAsync<OrderWithStatus>();
73+
}
74+
catch (Exception ex)
75+
{
76+
invalidOrder = true;
77+
pollingCancellationToken.Cancel();
78+
Console.Error.WriteLine(ex);
79+
}
7280

73-
StateHasChanged();
81+
StateHasChanged();
7482

75-
await Task.Delay(4000);
83+
await Task.Delay(4000);
84+
}
85+
}
86+
else
87+
{
88+
NavigationManager.NavigateTo(tokenResult.RedirectUrl);
7689
}
7790
}
7891

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
2+
3+
namespace BlazingPizza.Client
4+
{
5+
public class PizzaAuthenticationState : RemoteAuthenticationState
6+
{
7+
public Order Order { get; set; }
8+
}
9+
}

save-points/09-progressive-web-app/BlazingPizza.Client/Program.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Microsoft.AspNetCore.Components.Authorization;
1+
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
22
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
33
using Microsoft.Extensions.DependencyInjection;
44
using System.Threading.Tasks;
@@ -16,9 +16,12 @@ public static async Task Main(string[] args)
1616
builder.Services.AddScoped<OrderState>();
1717

1818
// Add auth services
19-
builder.Services.AddOptions();
20-
builder.Services.AddAuthorizationCore();
21-
builder.Services.AddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>();
19+
builder.Services.AddRemoteAuthentication<PizzaAuthenticationState, ApiAuthorizationProviderOptions>();
20+
builder.Services.AddApiAuthorization(options =>
21+
{
22+
options.AuthenticationPaths.LogOutSucceededPath = "";
23+
options.ProviderOptions.ConfigurationEndpoint = "_configuration/BlazingPizza.Client"; // temporary workaround
24+
});
2225

2326
await builder.Build().RunAsync();
2427
}

0 commit comments

Comments
 (0)