From 419a2321b8f1d394dbb6732f61169d93b5ff2caa Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 5 May 2025 11:15:19 -0400 Subject: [PATCH 1/2] Additional ServerWeatherForecaster scenarios --- aspnetcore/blazor/call-web-api.md | 17 ++++++-- .../security/blazor-web-app-with-entra.md | 2 +- aspnetcore/blazor/security/index.md | 41 ++++++++++++++++++- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/aspnetcore/blazor/call-web-api.md b/aspnetcore/blazor/call-web-api.md index 0beae83a9cef..5762f08a4f40 100644 --- a/aspnetcore/blazor/call-web-api.md +++ b/aspnetcore/blazor/call-web-api.md @@ -22,14 +22,25 @@ The [`System.Net.Http.Json`](https://www.nuget.org/packages/System.Net.Http.Json ## Use a token handler for web API calls -Blazor Web Apps with OIDC authentication can use a token handler approach to make outgoing requests to secure external web API calls. This approach is used by the `BlazorWebAppOidc` and `BlazorWebAppOidcServer` sample apps described in the next section. +Blazor Web Apps with OIDC authentication can use a token handler approach to make outgoing requests to secure external web API calls. This approach is used by the `BlazorWebAppOidc` and `BlazorWebAppOidcServer` sample apps described in the *Sample apps* section of this article. For more information, see the following resources: * * *Secure an ASP.NET Core Blazor Web App with OpenID Connect (OIDC)* - * [Non-BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-oidc?view=aspnetcore-9.0&pivots=non-bff-pattern) - * [Non-BFF pattern (Interactive Server)](xref:blazor/security/blazor-web-app-oidc?view=aspnetcore-9.0&pivots=non-bff-pattern-server) + * [Non-BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-oidc?pivots=non-bff-pattern) + * [Non-BFF pattern (Interactive Server)](xref:blazor/security/blazor-web-app-oidc?pivots=non-bff-pattern-server) + +## Microsoft identity platform for web API calls + +Blazor Web Apps that use use [Microsoft identity platform](/entra/identity-platform/)/[Microsoft Identity Web packages](/entra/msal/dotnet/microsoft-identity-web/) for [Microsoft Entra ID](https://www.microsoft.com/security/business/microsoft-entra) can make streamlined calls using Entra-specific API. This approach is used by the `BlazorWebAppEntra` and `BlazorWebAppEntraBff` sample apps described in the *Sample apps* section of this article. + +For more information, see the following resources: + +* +* *Secure an ASP.NET Core Blazor Web App with Microsoft Entra ID* + * [Non-BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-with-entra?pivots=non-bff-pattern) + * [BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-with-entra?pivots=non-bff-pattern-server) ## Sample apps diff --git a/aspnetcore/blazor/security/blazor-web-app-with-entra.md b/aspnetcore/blazor/security/blazor-web-app-with-entra.md index 8d8ec274a0dc..809804fedcac 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-entra.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-entra.md @@ -30,7 +30,7 @@ The following specification is covered: * The app uses [Microsoft Entra ID](https://www.microsoft.com/security/business/microsoft-entra), based on [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) packages. * Automatic non-interactive token refresh is managed by the framework. * The app uses server-side and client-side service abstractions to display generated weather data: - * When rendering the `Weather` component on the server to display weather data, the component uses the `ServerWeatherForecaster` on the server to directly obtain weather data (not via a web API call). + * When rendering the `Weather` component on the server to display weather data, the component uses the `ServerWeatherForecaster` on the server to obtain weather data. * When the `Weather` component is rendered on the client, the component uses the `ClientWeatherForecaster` service implementation, which uses a preconfigured (in the client project's `Program` file) to make a web API call to the server project's Minimal API (`/weather-forecast`) for weather data. The Minimal API endpoint obtains the weather data from the `ServerWeatherForecaster` class and returns it to the client for rendering by the component. ## Sample solution diff --git a/aspnetcore/blazor/security/index.md b/aspnetcore/blazor/security/index.md index ff89ffc55471..5b1f5427701f 100644 --- a/aspnetcore/blazor/security/index.md +++ b/aspnetcore/blazor/security/index.md @@ -772,7 +772,7 @@ else The server project implements `IWeatherForecaster` as `ServerWeatherForecaster`, which generates and returns mock weather data via its `GetWeatherForecastAsync` method: ```csharp -public class ServerWeatherForecaster() : IWeatherForecaster +internal sealed class ServerWeatherForecaster() : IWeatherForecaster { public readonly string[] summaries = [ @@ -797,6 +797,45 @@ public class ServerWeatherForecaster() : IWeatherForecaster } ``` +Alternatively, the `ServerWeatherForecaster` can call an external web API using a [named HTTP Client and token handler approach](xref:blazor/call-web-api#use-a-token-handler-for-web-API-calls), as the following example demonstrates: + +```csharp +internal sealed class ServerWeatherForecaster(IHttpClientFactory clientFactory) : IWeatherForecaster +{ + public async Task> GetWeatherForecastAsync() + { + var request = new HttpRequestMessage(HttpMethod.Get, "/weather-forecast"); + var client = clientFactory.CreateClient("ExternalApi"); + + var response = await client.SendAsync(request); + + response.EnsureSuccessStatusCode(); + + return await response.Content.ReadFromJsonAsync() ?? + throw new IOException("No weather forecast!"); + } +} +``` + +If the app uses [Microsoft identity platform](/entra/identity-platform/)/[Microsoft Identity Web packages](/entra/msal/dotnet/microsoft-identity-web/) for [Microsoft Entra ID](https://www.microsoft.com/security/business/microsoft-entra) (see ), the `ServerWeatherForecaster` might appear like the following class to make external web API calls: + +```csharp +internal sealed class ServerWeatherForecaster(IDownstreamApi downstreamApi) : IWeatherForecaster +{ + public async Task> GetWeatherForecastAsync() + { + var response = await downstreamApi.CallApiForUserAsync("DownstreamApi", + options => + { + options.RelativePath = "/weather-forecast"; + }); + + return await response.Content.ReadFromJsonAsync() ?? + throw new IOException("No weather forecast!"); + } +} +``` + The server project maintains a secure web API endpoint for client weather data calls: ```csharp From 4df1b4e3b4e5d6408c815ccc6b0dab027fc7b3f7 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 5 May 2025 11:26:48 -0400 Subject: [PATCH 2/2] Updates --- aspnetcore/blazor/call-web-api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/call-web-api.md b/aspnetcore/blazor/call-web-api.md index 5762f08a4f40..eab24ab47352 100644 --- a/aspnetcore/blazor/call-web-api.md +++ b/aspnetcore/blazor/call-web-api.md @@ -39,8 +39,8 @@ For more information, see the following resources: * * *Secure an ASP.NET Core Blazor Web App with Microsoft Entra ID* - * [Non-BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-with-entra?pivots=non-bff-pattern) - * [BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-with-entra?pivots=non-bff-pattern-server) + * [Non-BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-entra?pivots=non-bff-pattern) + * [BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-entra?pivots=non-bff-pattern-server) ## Sample apps