Skip to content

Commit ea3e1ad

Browse files
authored
Merge pull request #35485 from dotnet/main
2 parents 5d7c8f0 + fe1cd76 commit ea3e1ad

File tree

12 files changed

+239
-19
lines changed

12 files changed

+239
-19
lines changed

aspnetcore/blazor/host-and-deploy/webassembly/azure-static-web-apps.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ To deploy from Visual Studio, create a publish profile for Azure Static Web Apps
3030

3131
After the publish profile is created, deploy the app to the Azure Static Web Apps instance using the publish profile by selecting the **Publish** button.
3232

33-
## Deploy from Visual Studio Code
33+
## GitHub deployment scenarios
3434

35-
To deploy from Visual Studio Code, see [Quickstart: Build your first static site with Azure Static Web Apps](/azure/static-web-apps/getting-started?tabs=blazor).
36-
37-
## Deploy from GitHub
38-
39-
To deploy from a GitHub repository, see [Tutorial: Building a static web app with Blazor in Azure Static Web Apps](/azure/static-web-apps/deploy-blazor).
35+
* Visual Studio Code: [Quickstart: Build your first static site with Azure Static Web Apps](/azure/static-web-apps/getting-started?tabs=blazor)
36+
* .NET CLI: [Deploy Blazor websites to the cloud with Azure Static Web Apps (Video)](/shows/deploy-websites-to-the-cloud-with-azure-static-web-apps/deploy-blazor-websites-to-the-cloud-with-azure-static-web-apps)
37+
* Deploy from GitHub: [Tutorial: Building a static web app with Blazor in Azure Static Web Apps](/azure/static-web-apps/deploy-blazor)

aspnetcore/blazor/security/blazor-web-app-with-oidc.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ zone_pivot_groups: blazor-web-app-oidc-specification
1515

1616
This article describes how to secure a Blazor Web App with [OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/) using a sample app in the [`dotnet/blazor-samples` GitHub repository (.NET 8 or later)](https://github.com/dotnet/blazor-samples) ([how to download](xref:blazor/fundamentals/index#sample-apps)).
1717

18-
:::moniker-range=">= aspnetcore-9.0"
18+
:::zone pivot="non-bff-pattern"
19+
20+
:::moniker range=">= aspnetcore-9.0"
1921

2022
For Microsoft Entra ID or Azure AD B2C, you can use <xref:Microsoft.Identity.Web.AppBuilderExtension.AddMicrosoftIdentityWebApp%2A> from [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) ([`Microsoft.Identity.Web` NuGet package](https://www.nuget.org/packages/Microsoft.Identity.Web), [API documentation](<xref:Microsoft.Identity.Web?displayProperty=fullName>)), which adds both the OIDC and Cookie authentication handlers with the appropriate defaults. The sample app and the guidance in this article don't use Microsoft Identity Web. The guidance demonstrates how to configure the OIDC handler *manually* for any OIDC provider. For more information on implementing Microsoft Identity Web, see <xref:blazor/security/blazor-web-app-entra>.
2123

2224
:::moniker-end
2325

24-
:::zone pivot="non-bff-pattern"
25-
2626
This version of the article covers implementing OIDC without adopting the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends) with an app that adopts global Interactive Auto rendering (server and `.Client` projects). The BFF pattern is useful for making authenticated requests to external services. Change the article version selector to **BFF pattern** if the app's specification calls for adopting the BFF pattern.
2727

2828
The following specification is adopted:
@@ -377,6 +377,12 @@ The sample app only provides a user name and email for display purposes.
377377

378378
:::zone pivot="non-bff-pattern-server"
379379

380+
:::moniker range=">= aspnetcore-9.0"
381+
382+
For Microsoft Entra ID or Azure AD B2C, you can use <xref:Microsoft.Identity.Web.AppBuilderExtension.AddMicrosoftIdentityWebApp%2A> from [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) ([`Microsoft.Identity.Web` NuGet package](https://www.nuget.org/packages/Microsoft.Identity.Web), [API documentation](<xref:Microsoft.Identity.Web?displayProperty=fullName>)), which adds both the OIDC and Cookie authentication handlers with the appropriate defaults. The sample app and the guidance in this article don't use Microsoft Identity Web. The guidance demonstrates how to configure the OIDC handler *manually* for any OIDC provider. For more information on implementing Microsoft Identity Web, see <xref:blazor/security/blazor-web-app-entra>.
383+
384+
:::moniker-end
385+
380386
This version of the article covers implementing OIDC without adopting the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends) with an app that adopts global Interactive Server rendering (single project). The BFF pattern is useful for making authenticated requests to external services. Change the article version selector to **BFF pattern** if the app's specification calls for adopting the BFF pattern with global Interactive Auto rendering.
381387

382388
The following specification is adopted:
@@ -720,6 +726,12 @@ oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator
720726

721727
:::zone pivot="bff-pattern"
722728

729+
:::moniker range=">= aspnetcore-9.0"
730+
731+
For Microsoft Entra ID or Azure AD B2C, you can use <xref:Microsoft.Identity.Web.AppBuilderExtension.AddMicrosoftIdentityWebApp%2A> from [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) ([`Microsoft.Identity.Web` NuGet package](https://www.nuget.org/packages/Microsoft.Identity.Web), [API documentation](<xref:Microsoft.Identity.Web?displayProperty=fullName>)), which adds both the OIDC and Cookie authentication handlers with the appropriate defaults. The sample app and the guidance in this article don't use Microsoft Identity Web. The guidance demonstrates how to configure the OIDC handler *manually* for any OIDC provider. For more information on implementing Microsoft Identity Web, see <xref:blazor/security/blazor-web-app-entra>.
732+
733+
:::moniker-end
734+
723735
This version of the article covers implementing OIDC with the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends). If the app's specification doesn't call for adopting the BFF pattern, change the article version selector to **Non-BFF pattern (Interactive Auto)** (Interactive Auto rendering) or **Non-BFF pattern (Interactive Server)** (Interactive Server rendering).
724736

725737
## Prerequisites

aspnetcore/fundamentals/openapi/customize-openapi.md

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to customize OpenAPI documents in an ASP.NET Core app
55
ms.author: safia
66
monikerRange: '>= aspnetcore-9.0'
77
ms.custom: mvc
8-
ms.date: 10/26/2024
8+
ms.date: 05/15/2025
99
uid: fundamentals/openapi/customize-openapi
1010
---
1111
# Customize OpenAPI documents
@@ -44,18 +44,18 @@ Transformers can be registered onto the document by calling the <xref:Microsoft.
4444

4545
### Execution order for transformers
4646

47-
Transformers are executed as follows:
47+
Transformers execute in the following order:
4848

49-
* Schema transformers are executed when a schema is registered to the document. Schema transformers are executed in the order in which they were added.
50-
All schemas are added to the document before any operation processing occurs, so all schema transformers are executed before any operation transformers.
51-
* Operation transformers are executed when an operation is added to the document. Operation transformers are executed in the order in which they were added.
52-
All operations are added to the document before any document transformers are executed.
53-
* Document transformers are executed when the document is generated. This is the final pass over the document, and all operations and schemas have been add by this point.
54-
* When an app is configured to generate multiple OpenAPI documents, transformers are executed for each document independently.
49+
* Schema transformers execute when a schema is registered to the document. They execute in the order they're added.
50+
All schemas are added to the document before any operation processing occurs, so schema transformers execute before operation transformers.
51+
* Operation transformers execute when an operation is added to the document. They execute in the order they're added.
52+
All operations are added to the document before any document transformers execute.
53+
* Document transformers execute when the document is generated. This is the final pass over the document, and all operations and schemas are added by this point.
54+
* When an app is configured to generate multiple OpenAPI documents, transformers execute for each document independently.
5555

5656
For example, in the following snippet:
5757
* `SchemaTransformer2` is executed and has access to the modifications made by `SchemaTransformer1`.
58-
* Both `OperationTransformer1` and `OperationTransformer2` have access to the modifications made by both schema transformers for the types involved in the operation they are called to process.
58+
* Both `OperationTransformer1` and `OperationTransformer2` have access to the modifications made by both schema transformers for the types involved in the operation they're called to process.
5959
* `OperationTransformer2` is executed after `OperationTransformer1`, so it has access to the modifications made by `OperationTransformer1`.
6060
* Both `DocumentTransformer1` and `DocumentTransformer2` are executed after all operations and schemas have been added to the document, so they have access to all modifications made by the operation and schema transformers.
6161
* `DocumentTransformer2` is executed after `DocumentTransformer1`, so it has access to the modifications made by `DocumentTransformer1`.
@@ -119,6 +119,22 @@ For example, the following schema transformer sets the `format` of decimal types
119119

120120
[!code-csharp[](~/fundamentals/openapi/samples/10.x/WebMinOpenApi/Program.cs?name=snippet_schematransformer1)]
121121

122+
## Support for generating OpenApiSchemas in transformers
123+
<!-- https://github.com/dotnet/aspnetcore/pull/61050 -->
124+
125+
Developers can generate a schema for a C# type using the same logic as ASP.NET Core OpenAPI document generation and add it to the OpenAPI document. The schema can then be referenced from elsewhere in the OpenAPI document. This capability is available starting with .NET 10.
126+
127+
The context passed to document, operation, and schema transformers includes a new `GetOrCreateSchemaAsync` method that can be used to generate a schema for a type.
128+
This method also has an optional `ApiParameterDescription` parameter to specify additional metadata for the generated schema.
129+
130+
To support adding the schema to the OpenAPI document, a `Document` property has been added to the Operation and Schema transformer contexts. This allows any transformer to add a schema to the OpenAPI document using the document's `AddComponent` method.
131+
132+
### Example
133+
134+
To use this feature in a document, operation, or schema transformer, create the schema using the `GetOrCreateSchemaAsync` method provided in the context and add it to the OpenAPI document using the document's `AddComponent` method.
135+
136+
:::code language="csharp" source="~/fundamentals/openapi/samples/10.x/WebAppOpenAPI10/Program.cs" id="snippet_Generate_OpenApiSchemas_for_type" highlight="6-7":::
137+
122138
## Customize schema reuse
123139

124140
After all transformers have been applied, the framework makes a pass over the document to transfer certain schemas
@@ -145,7 +161,7 @@ that uses the name of the type, but you can replace it with your own implementat
145161
As a simple example of this customization, you might choose to always inline enum schemas.
146162
This is done by setting <xref:Microsoft.AspNetCore.OpenApi.OpenApiOptions.CreateSchemaReferenceId> to a delegate
147163
that returns null for enum types, and otherwise returns the value from the default implementation.
148-
The following code shows how to do this:
164+
The following code demonstrates this:
149165

150166
```csharp
151167
builder.Services.AddOpenApi(options =>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
3+
namespace WebAppOpenAPI10.Controllers
4+
{
5+
[ApiController]
6+
[Route("[controller]")]
7+
public class WeatherForecastController : ControllerBase
8+
{
9+
private static readonly string[] Summaries =
10+
[
11+
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
12+
];
13+
14+
[HttpGet(Name = "GetWeatherForecast")]
15+
public IEnumerable<WeatherForecast> Get()
16+
{
17+
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
18+
{
19+
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
20+
TemperatureC = Random.Shared.Next(-20, 55),
21+
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
22+
})
23+
.ToArray();
24+
}
25+
}
26+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#define SCHEMA_IN_TRANSFORMER_EXAMPLE //YAML_EXAMPLE //SCHEMA_IN_TRANSFORMER_EXAMPLE
2+
#if YAML_EXAMPLE
3+
4+
var builder = WebApplication.CreateBuilder(args);
5+
6+
// Add services to the container.
7+
builder.Services.AddControllers();
8+
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
9+
// <snippet_DefaultOpenApiVersion>
10+
builder.Services.AddOpenApi(options =>
11+
{
12+
options.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_1;
13+
});
14+
// </snippet_DefaultOpenApiVersion>
15+
16+
var app = builder.Build();
17+
18+
// Configure the HTTP request pipeline.
19+
// <snippet_ConfigOpenApiYAML>
20+
if (app.Environment.IsDevelopment())
21+
{
22+
app.MapOpenApi("/openapi/{documentName}.yaml");
23+
}
24+
// </snippet_ConfigOpenApiYAML>
25+
26+
app.UseHttpsRedirection();
27+
28+
app.UseAuthorization();
29+
30+
app.MapControllers();
31+
32+
app.Run();
33+
34+
#elif SCHEMA_IN_TRANSFORMER_EXAMPLE
35+
36+
var builder = WebApplication.CreateBuilder(args);
37+
38+
// Add services to the container.
39+
builder.Services.AddControllers();
40+
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
41+
// <snippet_Generate_OpenApiSchemas_for_type>
42+
builder.Services.AddOpenApi(options =>
43+
{
44+
options.AddOperationTransformer(async (operation, context, cancellationToken) =>
45+
{
46+
// Generate schema for error responses
47+
var errorSchema = await context.GetOrCreateSchemaAsync(typeof(ProblemDetails), null, cancellationToken);
48+
context.Document?.AddComponent("Error", errorSchema);
49+
50+
operation.Responses ??= new OpenApiResponses();
51+
// Add a "4XX" response to the operation with the newly created schema
52+
operation.Responses["4XX"] = new OpenApiResponse
53+
{
54+
Description = "Bad Request",
55+
Content = new Dictionary<string, OpenApiMediaType>
56+
{
57+
["application/problem+json"] = new OpenApiMediaType
58+
{
59+
Schema = new OpenApiSchemaReference("Error", context.Document)
60+
}
61+
}
62+
};
63+
});
64+
});
65+
// </snippet_Generate_OpenApiSchemas_for_type>
66+
67+
var app = builder.Build();
68+
69+
// Configure the HTTP request pipeline.
70+
if (app.Environment.IsDevelopment())
71+
{
72+
app.MapOpenApi("/openapi/{documentName}.yaml");
73+
}
74+
75+
app.UseHttpsRedirection();
76+
77+
app.UseAuthorization();
78+
79+
app.MapControllers();
80+
81+
app.Run();
82+
83+
#endif
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
options.AddSchemaTransformer((schema, context, cancellationToken) =>
2+
{
3+
if (context.JsonTypeInfo.Type == typeof(WeatherForecast))
4+
{
5+
- schema.Example = new OpenApiObject
6+
+ schema.Example = new JsonObject
7+
{
8+
- ["date"] = new OpenApiString(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd")),
9+
+ ["date"] = DateTime.Now.AddDays(1).ToString("yyyy-MM-dd"),
10+
- ["temperatureC"] = new OpenApiInteger(0),
11+
+ ["temperatureC"] = 0,
12+
- ["temperatureF"] = new OpenApiInteger(32),
13+
+ ["temperatureF"] = 32,
14+
- ["summary"] = new OpenApiString("Bracing"),
15+
+ ["summary"] = "Bracing",
16+
};
17+
}
18+
return Task.CompletedTask;
19+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace WebAppOpenAPI10
2+
{
3+
public class WeatherForecast
4+
{
5+
public DateOnly Date { get; set; }
6+
7+
public int TemperatureC { get; set; }
8+
9+
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
10+
11+
public string? Summary { get; set; }
12+
}
13+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<!-- <snippet_ConfigBuildTimeOpenApiDocVersion> -->
4+
<PropertyGroup>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
9+
<!-- Configure build-time OpenAPI generation to produce an OpenAPI 3.1 document. -->
10+
<OpenApiGenerateDocumentsOptions>--openapi-version OpenApi3_1</OpenApiGenerateDocumentsOptions>
11+
</PropertyGroup>
12+
<!-- </snippet_ConfigBuildTimeOpenApiDocVersion> -->
13+
14+
<ItemGroup>
15+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0-preview.4.24272.1" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@WebAppOpenAPI10_HostAddress = http://localhost:5077
2+
3+
GET {{WebAppOpenAPI10_HostAddress}}/weatherforecast/
4+
Accept: application/json
5+
6+
###
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
}
8+
}

0 commit comments

Comments
 (0)