diff --git a/.github/policies/pullRequestManagement-labelFiles.yml b/.github/policies/pullRequestManagement-labelFiles.yml index a6d8e6607dc9..8256fcb3fe0e 100644 --- a/.github/policies/pullRequestManagement-labelFiles.yml +++ b/.github/policies/pullRequestManagement-labelFiles.yml @@ -50,7 +50,5 @@ configuration: then: - requestReview: reviewer: guardrex - - addLabel: - label: 'blazor/subsvc' onFailure: onSuccess: diff --git a/aspnetcore/blazor/blazor-ef-core.md b/aspnetcore/blazor/blazor-ef-core.md index cd535e63103e..246cfde74755 100644 --- a/aspnetcore/blazor/blazor-ef-core.md +++ b/aspnetcore/blazor/blazor-ef-core.md @@ -3,9 +3,9 @@ title: ASP.NET Core Blazor with Entity Framework Core (EF Core) author: guardrex description: Learn how to use Entity Framework Core (EF Core) in Blazor apps. monikerRange: '>= aspnetcore-3.1' -ms.author: jeliknes +ms.author: riande ms.custom: mvc -ms.date: 11/12/2024 +ms.date: 01/16/2025 uid: blazor/blazor-ef-core --- # ASP.NET Core Blazor with Entity Framework Core (EF Core) @@ -33,7 +33,7 @@ This guidance applies to the **`Server`** project of a hosted Blazor WebAssembly ## Secure authentication flow required for production apps -This article uses a local database that doesn't require user authentication. Production apps should use the most secure authentication flow available. For more information on authentication for deployed test and production Blazor apps, see the articles in the [Blazor *Security and Identity* node](xref:blazor/security/index). +This article pertains to the use of a local database that doesn't require user authentication. Production apps should use the most secure authentication flow available. For more information on authentication for deployed test and production Blazor apps, see the articles in the [Blazor *Security and Identity* node](xref:blazor/security/index). For Microsoft Azure services, we recommend using *managed identities*. Managed identities securely authenticate to Azure services without storing credentials in app code. For more information, see the following resources: @@ -42,121 +42,11 @@ For Microsoft Azure services, we recommend using *managed identities*. Managed i * [Managed identities in Microsoft Entra for Azure SQL](/azure/azure-sql/database/authentication-azure-ad-user-assigned-managed-identity) * [How to use managed identities for App Service and Azure Functions](/azure/app-service/overview-managed-identity) -## Sample app - -The sample app was built as a reference for server-side Blazor apps that use EF Core. The sample app includes a grid with sorting and filtering, delete, add, and update operations. - -:::moniker range=">= aspnetcore-8.0" - -[View or download sample code](https://github.com/dotnet/blazor-samples) ([how to download](xref:blazor/fundamentals/index#sample-apps)): Select the folder that matches the version of .NET that you're adopting. Within the version folder, access the sample named `BlazorWebAppEFCore`. - -:::moniker-end - -:::moniker range="< aspnetcore-8.0" - -[View or download sample code](https://github.com/dotnet/blazor-samples) ([how to download](xref:blazor/fundamentals/index#sample-apps)): Select the folder that matches the version of .NET that you're adopting. Within the version folder, access the sample named `BlazorServerEFCoreSample`. - -:::moniker-end - -### Use the sample with SQLite - -The sample uses a local [SQLite](https://www.sqlite.org/index.html) database so that it can be used on any platform. - -The sample demonstrates use of EF Core to handle optimistic concurrency. However, [native database-generated concurrency tokens](/ef/core/saving/concurrency?tabs=fluent-api#native-database-generated-concurrency-tokens) aren't supported for SQLite databases, which is the database provider for the sample app. To demonstrate concurrency with the sample app, adopt a different database provider that supports database-generated concurrency tokens (for example, the [SQL Server provider](/ef/core/providers/sql-server)). You can adopt SQL Server for the sample app by following the guidance in the next section, *Use the sample with SQL Server and optimistic concurrency*. - -### Use the sample with SQL Server and optimistic concurrency - -The sample demonstrates use of EF Core to handle optimistic concurrency but only for a database provider that uses [native database-generated concurrency tokens](/ef/core/saving/concurrency?tabs=fluent-api#native-database-generated-concurrency-tokens), which is a feature supported for SQL Server. To demonstrate concurrency with the sample app, the sample app can be converted from the SQLite provider to use the [SQL Server provider](/ef/core/providers/sql-server) with a new SQL Server database created using .NET scaffolding. - -Use the following guidance to adopt SQL Server for the sample app using Visual Studio. - -Open the `Program` file (`Program.cs`) and comment out the lines that add the database context factory with the SQLite provider: - -```diff -- builder.Services.AddDbContextFactory(opt => -- opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")); -+ //builder.Services.AddDbContextFactory(opt => -+ // opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")); -``` - -Save the `Program.cs` file. - -Right-click the project in **Solution Explorer** and select **Add** > **New Scaffolded Item**. - -In the **Add New Scaffolded Item** dialog, select **Installed** > **Common** > **Blazor** > **Razor Component** > **Razor Components Using Entity Framework (CRUD)**. Select the **Add** button. - -In the **Add Razor Components Using Entity Framework (CRUD)** dialog, use the following settings: - -* **Template**: Use the default selection (**CRUD**). -* **Model class**: Select the `Contact` model from the dropdown list. -* **DbContext class**: Select the plus sign (`+`) and select **Add** using the default context class name generated by the scaffolder. -* **Database provider**: Use the default selection (**SQL Server**). - -Select **Add** to scaffold the model and create the SQL Server database. - -When the scaffolding operation completes, delete the generated context class from the `Data` folder (`Data/{PROJECT NAME}Context.cs`, where the `{PROJECT NAME}` placeholder is the project's name/namespace). - -Delete the `ContactPages` folder from the `Components/Pages` folder, which contains [QuickGrid](xref:blazor/components/quickgrid)-based pages for contact management. For a complete demonstration of QuickGrid-based pages for managing data, use the tutorial. - -Open the `Program` file (`Program.cs`) and find the line that scaffolding added to create a database context factory using the SQL Server provider. Change the context from the generated context class (deleted earlier) to the app's existing `ContactContext` class: - -```diff -- builder.Services.AddDbContextFactory(options => -+ builder.Services.AddDbContextFactory(options => -``` - -At this point, the app is using the SQL Server provider and a SQL Server database created for the `Contact` model class. Optimistic concurrency works using [native database-generated concurrency tokens](/ef/core/saving/concurrency?tabs=fluent-api#native-database-generated-concurrency-tokens) that are already implemented in the sample app's `ContactContext` class. - -### Database logging - -The sample also configures database logging to show the SQL queries that are generated. This is configured in `appsettings.Development.json`: - -:::moniker range=">= aspnetcore-9.0" - -:::code language="json" source="~/../blazor-samples/9.0/BlazorWebAppEFCore/appsettings.Development.json"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-8.0 < aspnetcore-9.0" - -:::code language="json" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/appsettings.Development.json"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - -:::code language="json" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/appsettings.Development.json"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - -:::code language="json" source="~/../blazor-samples/6.0/BlazorServerEFCoreSample/appsettings.Development.json"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - -:::code language="json" source="~/../blazor-samples/5.0/BlazorServerEFCoreSample/appsettings.Development.json"::: - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -:::code language="json" source="~/../blazor-samples/3.1/BlazorServerEFCoreSample/appsettings.Development.json"::: - -:::moniker-end - -The grid, add, and view components use the "context-per-operation" pattern, where a context is created for each operation. The edit component uses the "context-per-component" pattern, where a context is created for each component. - -> [!NOTE] -> Some of the code examples in this topic require namespaces and services that aren't shown. To inspect the fully working code, including the required [`@using`](xref:mvc/views/razor#using) and [`@inject`](xref:mvc/views/razor#inject) directives for Razor examples, see the [sample app](#sample-app). - :::moniker range=">= aspnetcore-8.0" ## Build a Blazor movie database app tutorial -For a tutorial experience building an app that uses EF Core to work with a database, see . The tutorial shows you how to create a Blazor Web App that can display and manage movies in a movie database. +For a tutorial experience building an app that uses EF Core for database operations, see . The tutorial shows you how to create a Blazor Web App that can display and manage movies in a movie database. :::moniker-end @@ -173,9 +63,9 @@ The following recommendations are designed to provide a consistent approach to u * Consider using one context per operation. The context is designed for fast, low overhead instantiation: ```csharp - using var context = new MyContext(); + using var context = new ProductsDatabaseContext(); - return await context.MyEntities.ToListAsync(); + return await context.Products.ToListAsync(); ``` * Use a flag to prevent multiple concurrent operations: @@ -198,13 +88,13 @@ The following recommendations are designed to provide a consistent approach to u } ``` - Place operations after the `Loading = true;` line in the `try` block. + Place database operations after the `Loading = true;` line in the `try` block. Thread safety isn't a concern, so loading logic doesn't require locking database records. The loading logic is used to disable UI controls so that users don't inadvertently select buttons or update fields while data is fetched. -* If there's any chance that multiple threads may access the same code block, [inject a factory](#scope-to-the-component-lifetime) and make a new instance per operation. Otherwise, injecting and using the context is usually sufficient. +* If there's any chance that multiple threads may access the same code block, [inject a factory](#scope-a-database-context-to-the-lifetime-of-the-component) and make a new instance per operation. Otherwise, injecting and using the context is usually sufficient. -* For longer-lived operations that take advantage of EF Core's [change tracking](/ef/core/querying/tracking) or [concurrency control](/ef/core/saving/concurrency), [scope the context to the lifetime of the component](#scope-to-the-component-lifetime). +* For longer-lived operations that take advantage of EF Core's [change tracking](/ef/core/querying/tracking) or [concurrency control](/ef/core/saving/concurrency), [scope the context to the lifetime of the component](#scope-a-database-context-to-the-lifetime-of-the-component). ## New `DbContext` instances @@ -219,214 +109,121 @@ The recommended approach to create a new + : IDbContextFactory where TContext : DbContext + { + private readonly IServiceProvider provider; + + public DbContextFactory(IServiceProvider provider) + { + this.provider = provider ?? throw new ArgumentNullException( + $"{nameof(provider)}: You must configure an instance of " + + "IServiceProvider"); + } + + public TContext CreateDbContext() => + ActivatorUtilities.CreateInstance(provider); + } +} +``` In the preceding factory: * satisfies any dependencies via the service provider. -* is available in EF Core ASP.NET Core 5.0 or later, so the interface is [implemented in the sample app for ASP.NET Core 3.x](https://github.com/dotnet/blazor-samples/blob/main/3.1/BlazorServerEFCoreSample/Data/IDbContextFactory.cs). - -:::moniker-end - -The following example configures [SQLite](https://www.sqlite.org/index.html) and enables data logging. The code uses an extension method (`AddDbContextFactory`) to configure the database factory for DI and provide default options: - -:::moniker range=">= aspnetcore-9.0" - -:::code language="csharp" source="~/../blazor-samples/9.0/BlazorWebAppEFCore/Program.cs" id="snippet1"::: +* is available in EF Core ASP.NET Core 5.0 or later, so the preceding interface is only required for ASP.NET Core 3.x. :::moniker-end -:::moniker range=">= aspnetcore-8.0 < aspnetcore-9.0" +The following example configures [SQLite](https://www.sqlite.org/index.html) and enables data logging in an app that manages contacts. The code uses an extension method () to configure the database factory for DI and provide default options: -:::code language="csharp" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/Program.cs" id="snippet1"::: +:::moniker range=">= aspnetcore-6.0" -:::moniker-end - -:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - -:::code language="csharp" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/Program.cs" id="snippet1"::: +```csharp +builder.Services.AddDbContextFactory(opt => + opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")); +``` :::moniker-end -:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" +:::moniker range="< aspnetcore-6.0" -:::code language="csharp" source="~/../blazor-samples/6.0/BlazorServerEFCoreSample/Program.cs" id="snippet1"::: +```csharp +services.AddDbContextFactory(opt => + opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")); +``` :::moniker-end -:::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - -:::code language="csharp" source="~/../blazor-samples/5.0/BlazorServerEFCoreSample/Startup.cs" id="snippet1"::: - -:::moniker-end +The factory is injected into components to create new instances. -:::moniker range="< aspnetcore-5.0" +## Scope a database context to a component method -:::code language="csharp" source="~/../blazor-samples/3.1/BlazorServerEFCoreSample/Startup.cs" id="snippet1"::: - -:::moniker-end - -The factory is injected into components and used to create new `DbContext` instances. - -In the home page of the sample app, `IDbContextFactory` is injected into the component: +The factory is injected into the component: ```razor @inject IDbContextFactory DbFactory ``` -A `DbContext` is created using the factory (`DbFactory`) to delete a contact in the `DeleteContactAsync` method: - -:::moniker range=">= aspnetcore-9.0" - -:::code language="razor" source="~/../blazor-samples/9.0/BlazorWebAppEFCore/Components/Pages/Home.razor" id="snippet1"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-8.0 < aspnetcore-9.0" - -:::code language="razor" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/Components/Pages/Home.razor" id="snippet1"::: - -:::moniker-end +Create a for a method using the factory (`DbFactory`): -:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - -:::code language="razor" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/Pages/Index.razor" id="snippet1"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - -:::code language="razor" source="~/../blazor-samples/6.0/BlazorServerEFCoreSample/Pages/Index.razor" id="snippet1"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - -:::code language="razor" source="~/../blazor-samples/5.0/BlazorServerEFCoreSample/Pages/Index.razor" id="snippet1"::: - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -:::code language="razor" source="~/../blazor-samples/3.1/BlazorServerEFCoreSample/Pages/Index.razor" id="snippet1"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-8.0" - -> [!NOTE] -> `Filters` is an injected `IContactFilters`, and `Wrapper` is a [component reference](xref:blazor/components/index#capture-references-to-components) to the `GridWrapper` component. See the `Home` component (`Components/Pages/Home.razor`) in the sample app. - -:::moniker-end - -:::moniker range="< aspnetcore-8.0" - -> [!NOTE] -> `Filters` is an injected `IContactFilters`, and `Wrapper` is a [component reference](xref:blazor/components/index#capture-references-to-components) to the `GridWrapper` component. See the `Index` component (`Pages/Index.razor`) in the sample app. - -:::moniker-end +```csharp +private async Task DeleteContactAsync() +{ + using var context = DbFactory.CreateDbContext(); + + if (context.Contacts is not null) + { + var contact = await context.Contacts.FirstAsync(...); + + if (contact is not null) + { + context.Contacts?.Remove(contact); + await context.SaveChangesAsync(); + } + } +} +``` -## Scope to the component lifetime +## Scope a database context to the lifetime of the component You may wish to create a that exists for the lifetime of a component. This allows you to use it as a [unit of work](https://martinfowler.com/eaaCatalog/unitOfWork.html) and take advantage of built-in features, such as change tracking and concurrency resolution. -:::moniker range=">= aspnetcore-8.0" - -You can use the factory to create a context and track it for the lifetime of the component. First, implement and inject the factory as shown in the `EditContact` component (`Components/Pages/EditContact.razor`): - -:::moniker-end - -:::moniker range="< aspnetcore-8.0" - -You can use the factory to create a context and track it for the lifetime of the component. First, implement and inject the factory as shown in the `EditContact` component (`Pages/EditContact.razor`): - -:::moniker-end +Implement and inject the factory into the component: ```razor @implements IDisposable @inject IDbContextFactory DbFactory ``` -The sample app ensures the context is disposed when the component is disposed: - -:::moniker range=">= aspnetcore-9.0" - -:::code language="csharp" source="~/../blazor-samples/9.0/BlazorWebAppEFCore/Components/Pages/EditContact.razor" id="snippet1"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-8.0 < aspnetcore-9.0" - -:::code language="csharp" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/Components/Pages/EditContact.razor" id="snippet1"::: - -:::moniker-end +Establish a property for the : -:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - -:::code language="csharp" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet1"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - -:::code language="csharp" source="~/../blazor-samples/6.0/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet1"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - -:::code language="csharp" source="~/../blazor-samples/5.0/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet1"::: - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -:::code language="csharp" source="~/../blazor-samples/3.1/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet1"::: - -:::moniker-end - -Finally, [`OnInitializedAsync`](xref:blazor/components/lifecycle) is overridden to create a new context. In the sample app, [`OnInitializedAsync`](xref:blazor/components/lifecycle) loads the contact in the same method: - -:::moniker range=">= aspnetcore-9.0" - -:::code language="csharp" source="~/../blazor-samples/9.0/BlazorWebAppEFCore/Components/Pages/EditContact.razor" id="snippet2"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-8.0 < aspnetcore-9.0" - -:::code language="csharp" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/Components/Pages/EditContact.razor" id="snippet2"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - -:::code language="csharp" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet2"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - -:::code language="csharp" source="~/../blazor-samples/6.0/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet2"::: - -:::moniker-end - -:::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - -:::code language="csharp" source="~/../blazor-samples/5.0/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet2"::: - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" +```csharp +private ContactContext? Context { get; set; } +``` -:::code language="csharp" source="~/../blazor-samples/3.1/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet2"::: +[`OnInitializedAsync`](xref:blazor/components/lifecycle) is overridden to create the : -In the preceding example: +```csharp +protected override async Task OnInitializedAsync() +{ + Context = DbFactory.CreateDbContext(); +} +``` -* When `Busy` is set to `true`, asynchronous operations may begin. When `Busy` is set back to `false`, asynchronous operations should be finished. -* Place additional error handling logic in a `catch` block. +The is disposed when the component is disposed: -:::moniker-end +```csharp +public void Dispose() => Context?.Dispose(); +``` ## Enable sensitive data logging diff --git a/aspnetcore/blazor/fundamentals/index.md b/aspnetcore/blazor/fundamentals/index.md index 18882eae41db..2a02c168a363 100644 --- a/aspnetcore/blazor/fundamentals/index.md +++ b/aspnetcore/blazor/fundamentals/index.md @@ -162,7 +162,7 @@ For more information, see the following resources: ## Subset of .NET APIs for Blazor WebAssembly apps -A curated list of specific .NET APIs that are supported on the browser for Blazor WebAssembly isn't available. However, you can manually [search for a list of .NET APIs annotated with `[UnsupportedOSPlatform("browser")]`](https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Runtime/Versioning/PlatformAttributes.cs,34041602e232c616,references) to discover .NET APIs that aren't supported in WebAssembly. +A curated list of specific .NET APIs that are supported on the browser for Blazor WebAssembly isn't available. However, you can manually [search for a list of .NET APIs annotated with `[UnsupportedOSPlatform("browser")]`](https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Runtime/Versioning/PlatformAttributes.cs,34041602e232c616,references) to discover .NET APIs that aren't supported in WebAssembly. [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] @@ -186,7 +186,6 @@ Samples apps in the repository: * Blazor Web App * Blazor WebAssembly * Blazor Web App Movies tutorial sample () -* Blazor Web App with EF Core () * Blazor Web App with SignalR () * Two Blazor Web Apps and a Blazor WebAssembly app for calling web (server) APIs () * Blazor Web App with OIDC (BFF and non-BFF patterns) () @@ -205,7 +204,6 @@ Samples apps in the repository: * Blazor Web App * Blazor WebAssembly * Blazor Web App Movies tutorial sample () -* Blazor Web App with EF Core () * Blazor Web App with SignalR () * Two Blazor Web Apps and a Blazor WebAssembly app for calling web (server) APIs () * Blazor Web App with OIDC (BFF and non-BFF patterns) () @@ -222,7 +220,6 @@ The sample repo contains two types of samples: * Snippet sample apps provide the code examples that appear in articles. These apps compile but aren't necessarily runnable apps. These apps are useful for merely obtaining example code that appears in articles. * Samples apps to accompany Blazor articles compile and run for the following scenarios: - * Blazor Server with EF Core * Blazor Server and Blazor WebAssembly with SignalR * Blazor WebAssembly scopes-enabled logging diff --git a/aspnetcore/blazor/host-and-deploy/webassembly.md b/aspnetcore/blazor/host-and-deploy/webassembly.md index c411e6e0a1d7..06a117482bb1 100644 --- a/aspnetcore/blazor/host-and-deploy/webassembly.md +++ b/aspnetcore/blazor/host-and-deploy/webassembly.md @@ -335,13 +335,13 @@ A *standalone deployment* serves the Blazor WebAssembly app as a set of static f Standalone deployment assets are published into either the `/bin/Release/{TARGET FRAMEWORK}/publish/wwwroot` or `bin\Release\{TARGET FRAMEWORK}\browser-wasm\publish\` folder (depending on the version of the .NET SDK in use), where the `{TARGET FRAMEWORK}` placeholder is the target framework. -### Azure App Service +## Azure App Service Blazor WebAssembly apps can be deployed to Azure App Services on Windows, which hosts the app on [IIS](#iis). Deploying a standalone Blazor WebAssembly app to Azure App Service for Linux isn't currently supported. We recommend hosting a standalone Blazor WebAssembly app using [Azure Static Web Apps](#azure-static-web-apps), which supports this scenario. -### Azure Static Web Apps +## Azure Static Web Apps Use one of the following approaches to deploy a Blazor WebAssembly app to Azure Static Web Apps: @@ -349,7 +349,7 @@ Use one of the following approaches to deploy a Blazor WebAssembly app to Azure * [Deploy from Visual Studio Code](#deploy-from-visual-studio-code) * [Deploy from GitHub](#deploy-from-github) -#### Deploy from Visual Studio +### Deploy from Visual Studio To deploy from Visual Studio, create a publish profile for Azure Static Web Apps: @@ -365,21 +365,21 @@ To deploy from Visual Studio, create a publish profile for Azure Static Web Apps 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. -#### Deploy from Visual Studio Code +### Deploy from Visual Studio Code 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). -#### Deploy from GitHub +### Deploy from GitHub 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). -### IIS +## IIS IIS is a capable static file server for Blazor apps. To configure IIS to host Blazor, see [Build a Static Website on IIS](/iis/manage/creating-websites/scenario-build-a-static-website-on-iis). Published assets are created in the `/bin/Release/{TARGET FRAMEWORK}/publish` or `bin\Release\{TARGET FRAMEWORK}\browser-wasm\publish` folder, depending on which version of the SDK is used and where the `{TARGET FRAMEWORK}` placeholder is the target framework. Host the contents of the `publish` folder on the web server or hosting service. -#### web.config +### web.config When a Blazor project is published, a `web.config` file is created with the following IIS configuration: @@ -391,7 +391,7 @@ When a Blazor project is published, a `web.config` file is created with the foll * Serve the sub-directory where the app's static assets reside (`wwwroot/{PATH REQUESTED}`). * Create SPA fallback routing so that requests for non-file assets are redirected to the app's default document in its static assets folder (`wwwroot/index.html`). -#### Use a custom `web.config` +### Use a custom `web.config` To use a custom `web.config` file: @@ -435,21 +435,21 @@ If the SDK's `web.config` generation or transformation during publish either doe ``` -#### Install the URL Rewrite Module +### Install the URL Rewrite Module The [URL Rewrite Module](https://www.iis.net/downloads/microsoft/url-rewrite) is required to rewrite URLs. The module isn't installed by default, and it isn't available for install as a Web Server (IIS) role service feature. The module must be downloaded from the IIS website. Use the Web Platform Installer to install the module: 1. Locally, navigate to the [URL Rewrite Module downloads page](https://www.iis.net/downloads/microsoft/url-rewrite#additionalDownloads). For the English version, select **WebPI** to download the WebPI installer. For other languages, select the appropriate architecture for the server (x86/x64) to download the installer. 1. Copy the installer to the server. Run the installer. Select the **Install** button and accept the license terms. A server restart isn't required after the install completes. -#### Configure the website +### Configure the website Set the website's **Physical path** to the app's folder. The folder contains: * The `web.config` file that IIS uses to configure the website, including the required redirect rules and file content types. * The app's static asset folder. -#### Host as an IIS sub-app +### Host as an IIS sub-app If a standalone app is hosted as an IIS sub-app, perform either of the following: @@ -486,7 +486,7 @@ Removing the handler or disabling inheritance is performed in addition to [confi Configure the app's base path by following the guidance in the article. -#### Brotli and Gzip compression +### Brotli and Gzip compression :::moniker range=">= aspnetcore-8.0" @@ -511,13 +511,13 @@ Additional configuration of the example `web.config` file might be required in t For more information on custom `web.config` files, see the [Use a custom `web.config`](#use-a-custom-webconfig) section. -#### Troubleshooting +### Troubleshooting If a *500 - Internal Server Error* is received and IIS Manager throws errors when attempting to access the website's configuration, confirm that the URL Rewrite Module is installed. When the module isn't installed, the `web.config` file can't be parsed by IIS. This prevents the IIS Manager from loading the website's configuration and the website from serving Blazor's static files. For more information on troubleshooting deployments to IIS, see . -### Azure Storage +## Azure Storage [Azure Storage](/azure/storage/) static file hosting allows serverless Blazor app hosting. Custom domain names, the Azure Content Delivery Network (CDN), and HTTPS are supported. @@ -538,7 +538,7 @@ If files aren't loaded at runtime due to inappropriate MIME types in the files' For more information, see [Static website hosting in Azure Storage](/azure/storage/blobs/storage-blob-static-website). -### Nginx +## Nginx The following `nginx.conf` file is simplified to show how to configure Nginx to send the `index.html` file whenever it can't find a corresponding file on disk. @@ -577,7 +577,7 @@ Increase the value if browser developer tools or a network traffic tool indicate For more information on production Nginx web server configuration, see [Creating NGINX Plus and NGINX Configuration Files](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/). -### Apache +## Apache To deploy a Blazor WebAssembly app to Apache: @@ -668,23 +668,67 @@ To deploy a Blazor WebAssembly app to Apache: For more information, see [`mod_mime`](https://httpd.apache.org/docs/2.4/mod/mod_mime.html) and [`mod_deflate`](https://httpd.apache.org/docs/current/mod/mod_deflate.html). -### GitHub Pages +## GitHub Pages -The default GitHub Action, which deploys pages, skips deployment of folders starting with underscore, for example, the `_framework` folder. To deploy folders starting with underscore, add an empty `.nojekyll` file to the Git branch. +The following guidance for GitHub Pages deployments of Blazor WebAssembly apps demonstrates concepts with a live tool deployed to GitHub Pages. The tool is used by the ASP.NET Core documentation authors to create cross-reference (XREF) links to API documentation for article markdown: -Git treats JavaScript (JS) files, such as `blazor.webassembly.js`, as text and converts line endings from CRLF (carriage return-line feed) to LF (line feed) in the deployment pipeline. These changes to JS files produce different file hashes than Blazor sends to the client in the `blazor.boot.json` file. The mismatches result in integrity check failures on the client. One approach to solving this problem is to add a `.gitattributes` file with `*.js binary` line before adding the app's assets to the Git branch. The `*.js binary` line configures Git to treat JS files as binary files, which avoids processing the files in the deployment pipeline. The file hashes of the unprocessed files match the entries in the `blazor.boot.json` file, and client-side integrity checks pass. For more information, see . +* [`BlazorWebAssemblyXrefGenerator` sample app (`blazor-samples/BlazorWebAssemblyXrefGenerator`)](https://github.com/dotnet/blazor-samples/tree/main/BlazorWebAssemblyXrefGenerator) +* [Live Xref Generator website](https://dotnet.github.io/blazor-samples/) -To handle URL rewrites, add a `wwwroot/404.html` file with a script that handles redirecting the request to the `index.html` page. For an example, see the [`SteveSandersonMS/BlazorOnGitHubPages` GitHub repository](https://github.com/SteveSandersonMS/BlazorOnGitHubPages): +### GitHub Pages settings -* [`wwwroot/404.html`](https://github.com/SteveSandersonMS/BlazorOnGitHubPages/blob/master/wwwroot/404.html) -* [Live site](https://stevesandersonms.github.io/BlazorOnGitHubPages/) +* **Actions** > **General** + * **Actions permissions** + * **Allow enterprise actions, and select non-enterprise, actions and reusable workflows** > Enabled (selected) + * **Allow actions created by GitHub** > Enabled (selected) + * **Allow actions and reusable workflows** > `stevesandersonms/ghaction-rewrite-base-href@v1,` + * **Workflow permissions** > **Read repository contents and packages permissions** +* **Pages** > **Build and deployment** + * **Source** > **GitHub Actions** + * Selected workflow: **Static HTML** and base your static deployment Action script on the [Xref Generator `static.yml` file](https://github.com/dotnet/blazor-samples/blob/main/.github/workflows/static.yml) for the Xref Generator tool. The configuration in the file is described in the next section. + * **Custom domain**: Set if you intend to use a custom domain, which isn't covered by this guidance. For more information, see [Configuring a custom domain for your GitHub Pages site](https://docs.github.com/pages/configuring-a-custom-domain-for-your-github-pages-site). + * **Enforce HTTPS** > Enabled (selected) -When using a project site instead of an organization site, update the `` tag in `wwwroot/index.html`. Set the `href` attribute value to the GitHub repository name with a trailing slash (for example, `/my-repository/`). In the [`SteveSandersonMS/BlazorOnGitHubPages` GitHub repository](https://github.com/SteveSandersonMS/BlazorOnGitHubPages), the base `href` is updated at publish by the [`.github/workflows/main.yml` configuration file](https://github.com/SteveSandersonMS/BlazorOnGitHubPages/blob/master/.github/workflows/main.yml). +### Static deployment script configuration -> [!NOTE] -> The [`SteveSandersonMS/BlazorOnGitHubPages` GitHub repository](https://github.com/SteveSandersonMS/BlazorOnGitHubPages) isn't owned, maintained, or supported by the .NET Foundation or Microsoft. +[Xref Generator `static.yml` file](https://github.com/dotnet/blazor-samples/blob/main/.github/workflows/static.yml) + +Configure the following entries in the script for your deployment: + +* Publish directory (`PUBLISH_DIR`): Use the path to the repository's folder where the Blazor WebAssembly app is published. The app is compiled for a specific .NET version, and the path segment for the version must match. Example: `BlazorWebAssemblyXrefGenerator/bin/Release/net9.0/publish/wwwroot` is the path for an app that adopts the `net9.0` [Target Framework Moniker (TFM)](/dotnet/standard/frameworks) for the .NET 9.0 SDK +* Push path (`on:push:paths`): Set the push path to match the app's repo folder with a `**` wildcard. Example: `BlazorWebAssemblyXrefGenerator/**` +* .NET SDK version (`dotnet-version` via the [`actions/setup-dotnet` Action](https://github.com/actions/setup-dotnet)): Currently, there's no way to set the version to "latest" (see [Allow specifying 'latest' as dotnet-version (`actions/setup-dotnet` #497)](https://github.com/actions/setup-dotnet/issues/497) to up-vote the feature request). Set the SDK version at least as high as the app's framework version. +* Publish path (`dotnet publish` command): Set the publish folder path to the app's repo folder. Example: `dotnet publish BlazorWebAssemblyXrefGenerator -c Release` +* Base HREF (`base_href` for the [`SteveSandersonMS/ghaction-rewrite-base-href` Action](https://github.com/SteveSandersonMS/ghaction-rewrite-base-href)): Set the base href for the app to the repository's name. Example: The Blazor sample's repository owner is `dotnet`. The Blazor sample's repository's name is `blazor-samples`. When the Xref Generator tool is deployed to GitHub Pages, its web address is based on the repository's name (`https://dotnet.github.io/blazor-samples/`). The base href of the app is `/blazor-samples/`, which is set into `base_href` for the `ghaction-rewrite-base-href` Action to write into the app's `wwwroot/index.html` `` tag when the app is deployed. For more information, see . + +The GitHub-hosted Ubuntu (latest) server has a version of the .NET SDK pre-installed. You can remove the [`actions/setup-dotnet` Action](https://github.com/actions/setup-dotnet) step from the `static.yml` script if the pre-installed .NET SDK is sufficient to compile the app. To determine the .NET SDK installed for `ubuntu-latest`: + +1. Go to the [**Available Images** section of the `actions/runner-images` GitHub repository](https://github.com/actions/runner-images?tab=readme-ov-file#available-images). +1. Locate the `ubuntu-latest` image, which is the first table row. +1. Select the link in the `Included Software` column. +1. Scroll down to the *.NET Tools* section to see the .NET Core SDK installed with the image. + +### Deployment notes + +The default GitHub Action, which deploys pages, skips deployment of folders starting with underscore, the `_framework` folder for example. To deploy folders starting with underscore, add an empty `.nojekyll` file to the root of the app's repository. Example: [Xref Generator `.nojekyll` file](https://github.com/dotnet/blazor-samples/blob/main/BlazorWebAssemblyXrefGenerator/.nojekyll) + +***Perform this step before the first app deployment:*** Git treats JavaScript (JS) files, such as `blazor.webassembly.js`, as text and converts line endings from CRLF (carriage return-line feed) to LF (line feed) in the deployment pipeline. These changes to JS files produce different file hashes than Blazor sends to the client in the `blazor.boot.json` file. The mismatches result in integrity check failures on the client. One approach to solving this problem is to add a `.gitattributes` file with `*.js binary` line before adding the app's assets to the Git branch. The `*.js binary` line configures Git to treat JS files as binary files, which avoids processing the files in the deployment pipeline. The file hashes of the unprocessed files match the entries in the `blazor.boot.json` file, and client-side integrity checks pass. For more information, see . Example: [Xref Generator `.gitattributes` file](https://github.com/dotnet/blazor-samples/blob/main/BlazorWebAssemblyXrefGenerator/.gitattributes) + +To handle URL rewrites based on [Single Page Apps for GitHub Pages (`rafrex/spa-github-pages` GitHub repository)](https://github.com/rafrex/spa-github-pages): + +* Add a `wwwroot/404.html` file with a script that handles redirecting the request to the `index.html` page. Example: [Xref Generator `404.html` file](https://github.com/dotnet/blazor-samples/blob/main/BlazorWebAssemblyXrefGenerator/wwwroot/404.html) +* In `wwwroot/index.html`, add the script to `` content. Example: [Xref Generator `index.html` file](https://github.com/dotnet/blazor-samples/blob/main/BlazorWebAssemblyXrefGenerator/wwwroot/index.html) + +GitHub Pages doesn't natively support using Brotli-compressed resources. To use Brotli: + +* Add the `wwwroot/decode.js` script to the app's `wwwroot` folder. Example: [Xref Generator `decode.js` file](https://github.com/dotnet/blazor-samples/blob/main/BlazorWebAssemblyXrefGenerator/wwwroot/decode.js) +* Add the ``) inside the [closing `` element](xref:blazor/project-structure#location-of-head-and-body-content) after the Blazor script reference: diff --git a/aspnetcore/blazor/security/gdpr.md b/aspnetcore/blazor/security/gdpr.md new file mode 100644 index 000000000000..bb8554b3cde2 --- /dev/null +++ b/aspnetcore/blazor/security/gdpr.md @@ -0,0 +1,251 @@ +--- +title: EU General Data Protection Regulation (GDPR) support in ASP.NET Core Blazor +author: guardrex +description: Learn how to implement EU General Data Protection Regulation (GDPR) support in Blazor apps. +monikerRange: '>= aspnetcore-6.0' +ms.author: riande +ms.custom: mvc +ms.date: 01/16/2025 +uid: blazor/security/gdpr +zone_pivot_groups: blazor-app-models +--- +# EU General Data Protection Regulation (GDPR) support in ASP.NET Core Blazor + +[!INCLUDE[](~/includes/not-latest-version.md)] + +This article explains how to implement support for [EU General Data Protection Regulation (GDPR)](https://ec.europa.eu/info/law/law-topic/data-protection/reform/what-does-general-data-protection-regulation-gdpr-govern_en) requirements. + +:::zone pivot="server" + +In the `Program` file: + +* Add configuration to require user consent for non-essential cookies and set the same-site policy to none. For more information, see . +* Add the default implementation for the service by calling . + +```csharp +builder.Services.Configure(options => +{ + options.CheckConsentNeeded = context => true; + + options.MinimumSameSitePolicy = SameSiteMode.None; +}); + +builder.Services.AddHttpContextAccessor(); +``` + +:::moniker range=">= aspnetcore-8.0" + +In the `Program` file before the call to , add Cookie Policy Middleware by calling : + +:::moniker-end + +:::moniker range="< aspnetcore-8.0" + +In the `Program` file before the call to , add Cookie Policy Middleware by calling : + +:::moniker-end + +```csharp +app.UseCookiePolicy(); +``` + +Add the following `CookieConsent` component to handle cookie policy consent. + +The component uses a [collocated JavaScript file](xref:blazor/js-interop/javascript-location#load-a-script-from-an-external-javascript-file-js-collocated-with-a-component), named `CookieConsent.razor.js`, to load a module. Confirm or adjust the path to the collocated file in the `OnAfterRenderAsync` method. The following component assumes that the component and its companion JavaScript file are in the `Components` folder of the app. + +`CookieConsent.razor`: + +```razor +@using Microsoft.AspNetCore.Http.Features +@using Microsoft.AspNetCore.Http +@implements IAsyncDisposable +@inject IHttpContextAccessor Http +@inject IJSRuntime JS + +@if (showBanner) +{ + +} +@code { + private IJSObjectReference? module; + private ITrackingConsentFeature? consentFeature; + private bool showBanner; + private string? cookieString; + + protected override void OnInitialized() + { + consentFeature = Http.HttpContext?.Features.Get(); + showBanner = !consentFeature?.CanTrack ?? false; + cookieString = consentFeature?.CreateConsentCookie(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + module = await JS.InvokeAsync("import", + "./Components/CookieConsent.razor.js"); + } + } + + private async Task AcceptPolicy() + { + if (module is not null) + { + await module.InvokeVoidAsync("acceptPolicy", cookieString); + showBanner = false; + } + } + + async ValueTask IAsyncDisposable.DisposeAsync() + { + if (module is not null) + { + try + { + await module.DisposeAsync(); + } + catch (JSDisconnectedException) + { + } + } + } +} +``` + +Add the following [collocated JavaScript file](xref:blazor/js-interop/javascript-location#load-a-script-from-an-external-javascript-file-js-collocated-with-a-component) to maintain the `acceptPolicy` function in a JavaScript module. + +`CookieConsent.razor.js`: + +```javascript +export function acceptPolicy(cookieString) { + document.cookie = cookieString; +} +``` + +Within `
` Razor markup of the `MainLayout` component (`MainLayout.razor`), add the `CookieConsent` component: + +```razor + +``` + +## Customize the cookie consent value + +Specify the cookie consent value by assigning a custom string to . The following example changes the default value of "`yes`" to "`true`": + +```csharp +options.ConsentCookieValue = "true"; +``` + +:::zone-end + +:::zone pivot="webassembly" + +In Blazor WebAssembly apps, [local storage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) is a convenient approach for maintaining a user's acceptance of a site's cookie policy. The following approach demonstrates the approach. + +If the app doesn't already have a `Shared` folder for shared components, add a `Shared` folder to the app. + +Add the namespace for shared components to the `_Imports.razor` file. In the following example, the app's namespace is `BlazorSample`, and the shared folder's namespace is `BlazorSample.Shared`: + +```razor +@using BlazorSample.Shared +``` + +Add the following `CookieConsent` component to handle cookie policy consent. + +`Shared/CookieConsent.razor`: + +```razor +@implements IAsyncDisposable +@inject IJSRuntime JS + +@if (showBanner) +{ + +} +@code { + private IJSObjectReference? module; + private bool showBanner = false; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + module = await JS.InvokeAsync("import", + "./Shared/CookieConsent.razor.js"); + showBanner = !await module.InvokeAsync("getCookiePolicyAccepted"); + StateHasChanged(); + } + } + + private async Task AcceptPolicy() + { + if (module is not null) + { + await module.InvokeVoidAsync("setCookiePolicyAccepted"); + showBanner = false; + } + } + + async ValueTask IAsyncDisposable.DisposeAsync() + { + if (module is not null) + { + try + { + await module.DisposeAsync(); + } + catch (JSDisconnectedException) + { + } + } + } +} +``` + +Add the following [collocated JavaScript file](xref:blazor/js-interop/javascript-location#load-a-script-from-an-external-javascript-file-js-collocated-with-a-component) to maintain the `setCookiePolicyAccepted` and `getCookiePolicyAccepted` functions in a JavaScript module. + +`Shared/CookieConsent.razor.js`: + +```javascript +export function getCookiePolicyAccepted() { + const cookiePolicy = localStorage.getItem('CookiePolicyAccepted'); + return cookiePolicy === 'yes' ? true : false; +} + +export function setCookiePolicyAccepted() { + localStorage.setItem('CookiePolicyAccepted', 'yes'); +} +``` + +In the preceding example, you can change the name of the local storage item and value from "`CookiePolicyAccepted`" and "`yes`" to any preferred values. If you change one or both values, update both functions. + +Within `
` Razor markup of the `MainLayout` component (`Layout/MainLayout.razor`), add the `CookieConsent` component: + +```razor + +``` + +:::zone-end + +## Additional resources + +* [Microsoft Trust Center: Safeguard individual privacy with cloud services from Microsoft: GDPR](https://www.microsoft.com/trust-center/privacy/gdpr-overview) +* [European Commission: Data protection explained](https://ec.europa.eu/info/law/law-topic/data-protection/reform/what-does-general-data-protection-regulation-gdpr-govern_en) diff --git a/aspnetcore/blazor/security/qrcodes-for-authenticator-apps.md b/aspnetcore/blazor/security/qrcodes-for-authenticator-apps.md index 6726d5e3d6cf..5b959f2ee1bf 100644 --- a/aspnetcore/blazor/security/qrcodes-for-authenticator-apps.md +++ b/aspnetcore/blazor/security/qrcodes-for-authenticator-apps.md @@ -104,6 +104,10 @@ The `EnableAuthenticator` component can be inspected in reference source: [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] +## Failures due to TOTP time skew + +TOTP authentication depends on accurate time keeping on the TOTP authenticator app device and the app's host. TOTP tokens are only valid for 30 seconds. If logins are failing due to rejected TOTP codes, confirm accurate time is maintained, preferably synchronized to an accurate NTP service. + ## Additional resources * [Using a different QR code library](xref:security/authentication/identity-enable-qrcodes#using-a-different-qr-code-library) diff --git a/aspnetcore/blazor/security/webassembly/standalone-with-identity/qrcodes-for-authenticator-apps.md b/aspnetcore/blazor/security/webassembly/standalone-with-identity/qrcodes-for-authenticator-apps.md index 07d390437e72..4d1922cf41de 100644 --- a/aspnetcore/blazor/security/webassembly/standalone-with-identity/qrcodes-for-authenticator-apps.md +++ b/aspnetcore/blazor/security/webassembly/standalone-with-identity/qrcodes-for-authenticator-apps.md @@ -882,6 +882,10 @@ In the `` content of the `` in `Components/Layout/Nav ``` +## Failures due to TOTP time skew + +TOTP authentication depends on accurate time keeping on the TOTP authenticator app device and the app's host. TOTP tokens are only valid for 30 seconds. If logins are failing due to rejected TOTP codes, confirm accurate time is maintained, preferably synchronized to an accurate NTP service. + ## Additional resources * [`nimiq/qr-creator`](https://github.com/nimiq/qr-creator) diff --git a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md index 6ebf1e4c3ff2..3a092aa83fad 100644 --- a/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md +++ b/aspnetcore/fundamentals/aot/request-delegate-generator/rdg-ids.md @@ -22,7 +22,7 @@ The ASP.NET Core Request Delegate Generator (RDG) is a tool that generates reque [!INCLUDE[](~/fundamentals/aot/includes/aot_preview.md)] -The following list contains the [RDG diagnostics](https://source.dot.net/#Microsoft.AspNetCore.Http.RequestDelegateGenerator/DiagnosticDescriptors.cs,44128aef6daa9b5e) for ASP.NET Core: +The following list contains the [RDG diagnostics](https://source.dot.net/#Microsoft.AspNetCore.Http.RequestDelegateGenerator/DiagnosticDescriptors.cs,44128aef6daa9b5e) for ASP.NET Core: HTTP/3 can be enabled by calling [builder.WebHost.UseQuic](xref:Microsoft.AspNetCore.Hosting.WebHostBuilderQuicExtensions.UseQuic%2A). +As noted earlier, the `CreateSlimBuilder` method doesn't include support for HTTPS or HTTP/3. These protocols typically aren't required for apps that run behind a TLS termination proxy. For example, see [TLS termination and end to end TLS with Application Gateway](/azure/application-gateway/ssl-overview). HTTPS can be enabled by calling +[builder.WebHost.UseKestrelHttpsConfiguration](/dotnet/api/microsoft.aspnetcore.hosting.webhostbuilderkestrelextensions.usekestrelhttpsconfiguration) HTTP/3 can be enabled by calling [builder.WebHost.UseQuic](xref:Microsoft.AspNetCore.Hosting.WebHostBuilderQuicExtensions.UseQuic%2A). ### `CreateSlimBuilder` vs `CreateBuilder` diff --git a/aspnetcore/fundamentals/native-aot/includes/native-aot8.md b/aspnetcore/fundamentals/native-aot/includes/native-aot8.md index c106acb1c3c2..27ddf3c017b6 100644 --- a/aspnetcore/fundamentals/native-aot/includes/native-aot8.md +++ b/aspnetcore/fundamentals/native-aot/includes/native-aot8.md @@ -185,7 +185,7 @@ The template uses the with the minimum ASP.NET Core features necessary to run an app. -As noted earlier, the `CreateSlimBuilder` method doesn't include support for HTTPS or HTTP/3. These protocols typically aren't required for apps that run behind a TLS termination proxy. For example, see [TLS termination and end to end TLS with Application Gateway](/azure/application-gateway/ssl-overview). HTTPS can be enabled by calling [builder.WebHost.UseKestrelHttpsConfiguration](https://source.dot.net/#Microsoft.AspNetCore.Server.Kestrel/WebHostBuilderKestrelExtensions.cs,fcec859000ccaa50) HTTP/3 can be enabled by calling [builder.WebHost.UseQuic](xref:Microsoft.AspNetCore.Hosting.WebHostBuilderQuicExtensions.UseQuic%2A). +As noted earlier, the `CreateSlimBuilder` method doesn't include support for HTTPS or HTTP/3. These protocols typically aren't required for apps that run behind a TLS termination proxy. For example, see [TLS termination and end to end TLS with Application Gateway](/azure/application-gateway/ssl-overview). HTTPS can be enabled by calling [builder.WebHost.UseKestrelHttpsConfiguration](/dotnet/api/microsoft.aspnetcore.hosting.webhostbuilderkestrelextensions.usekestrelhttpsconfiguration) HTTP/3 can be enabled by calling [builder.WebHost.UseQuic](xref:Microsoft.AspNetCore.Hosting.WebHostBuilderQuicExtensions.UseQuic%2A). ### `CreateSlimBuilder` vs `CreateBuilder` diff --git a/aspnetcore/fundamentals/openapi/aspnetcore-openapi.md b/aspnetcore/fundamentals/openapi/aspnetcore-openapi.md index 68409d790e3a..aa4decde9857 100644 --- a/aspnetcore/fundamentals/openapi/aspnetcore-openapi.md +++ b/aspnetcore/fundamentals/openapi/aspnetcore-openapi.md @@ -197,7 +197,7 @@ In order to restrict these code paths from being invoked by the build-time gener :::code language="csharp" source="~/fundamentals/openapi/samples/9.x/AspireApp1/AspireApp1.Web/Program.cs" highlight="5-8"::: -[AddServiceDefaults](https://source.dot.net/#TestingAppHost1.ServiceDefaults/Extensions.cs,0f0d863053754768,references) Adds common .NET Aspire services such as service discovery, resilience, health checks, and OpenTelemetry. +[AddServiceDefaults](https://source.dot.net/#TestingAppHost1.ServiceDefaults/Extensions.cs,0f0d863053754768,references) Adds common .NET Aspire services such as service discovery, resilience, health checks, and OpenTelemetry. :::moniker-end diff --git a/aspnetcore/fundamentals/servers/httpsys.md b/aspnetcore/fundamentals/servers/httpsys.md index 856e7ace8c09..a1ddf2d89cb8 100644 --- a/aspnetcore/fundamentals/servers/httpsys.md +++ b/aspnetcore/fundamentals/servers/httpsys.md @@ -288,11 +288,11 @@ For apps hosted by HTTP.sys that interact with requests from the Internet or a c -[IHttpSysRequestTimingFeature](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/IHttpSysRequestTimingFeature.cs,3c5dc86dc837b1f4) provides detailed timing information for requests: +[IHttpSysRequestTimingFeature](/dotnet/api/microsoft.aspnetcore.server.httpsys.ihttpsysrequesttimingfeature) provides detailed timing information for requests: * Timestamps are obtained using [QueryPerformanceCounter](/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter). * The timestamp frequency can be obtained via [QueryPerformanceFrequency](/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency). -* The index of the timing can be cast to [HttpSysRequestTimingType](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/HttpSysRequestTimingType.cs,e62e7bcd02f8589e) to know what the timing represents. +* The index of the timing can be cast to [HttpSysRequestTimingType](/dotnet/api/microsoft.aspnetcore.server.httpsys.httpsysrequesttimingtype) to know what the timing represents. * The value may be 0 if the timing isn't available for the current request. * Requires Windows 10 version 2004, Windows Server 2022, or later. @@ -302,7 +302,7 @@ For apps hosted by HTTP.sys that interact with requests from the Internet or a c :::code language="csharp" source="~/fundamentals/request-features/samples/8.x/IHttpSysRequestTimingFeature/Program.cs" id="snippet_WithTryGetTimestamp"::: -[IHttpSysRequestTimingFeature.TryGetElapsedTime](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/IHttpSysRequestTimingFeature.cs,3c5dc86dc837b1f4) gives the elapsed time between two specified timings: +[IHttpSysRequestTimingFeature.TryGetElapsedTime](/dotnet/api/microsoft.aspnetcore.server.httpsys.ihttpsysrequesttimingfeature.trygetelapsedtime yields the elapsed time between two specified timings: :::code language="csharp" source="~/fundamentals/request-features/samples/8.x/IHttpSysRequestTimingFeature/Program.cs" id="snippet_WithTryGetElapsedTime"::: diff --git a/aspnetcore/fundamentals/startup.md b/aspnetcore/fundamentals/startup.md index 363d8618e32a..fddb13f336a8 100644 --- a/aspnetcore/fundamentals/startup.md +++ b/aspnetcore/fundamentals/startup.md @@ -30,7 +30,7 @@ The following app startup code supports several app types: [!code-csharp[](~/fundamentals/startup/9.0_samples/WebAll/Program.cs?name=snippet)] -Apps that use can measure the startup time to understand and optimize startup performance. The [`ServerReady`](https://source.dot.net/#Microsoft.AspNetCore.Hosting/Internal/HostingEventSource.cs,76) event in represents the point where the server is ready to respond to requests. +Apps that use can measure the startup time to understand and optimize startup performance. The [`ServerReady`](https://source.dot.net/#Microsoft.AspNetCore.Hosting/Internal/HostingEventSource.cs,76) event in represents the point where the server is ready to respond to requests. diff --git a/aspnetcore/fundamentals/target-aspnetcore.md b/aspnetcore/fundamentals/target-aspnetcore.md index 45b0f83db115..d9c7bdc87658 100644 --- a/aspnetcore/fundamentals/target-aspnetcore.md +++ b/aspnetcore/fundamentals/target-aspnetcore.md @@ -187,7 +187,7 @@ Alternatively, .NET Standard 2.0 could be targeted instead of targeting both .NE With the preceding project file, the following caveats exist: -* Since the library only contains Tag Helpers, it's more straightforward to target the specific platforms on which ASP.NET Core runs: .NET Core and .NET Framework. Tag Helpers can't be used by other .NET Standard 2.0-compliant target frameworks such as Unity, UWP, and Xamarin. +* Since the library only contains Tag Helpers, it's more straightforward to target the specific platforms on which ASP.NET Core runs: .NET Core and .NET Framework. Tag Helpers can't be used by other .NET Standard 2.0-compliant target frameworks such as Unity and UWP. * Using .NET Standard 2.0 from .NET Framework has some issues that were addressed in .NET Framework 4.7.2. You can improve the experience for consumers using .NET Framework 4.6.1 through 4.7.1 by targeting .NET Framework 4.6.1. If your library needs to call platform-specific APIs, target specific .NET implementations instead of .NET Standard. For more information, see [Multi-targeting](/dotnet/standard/library-guidance/cross-platform-targeting#multi-targeting). diff --git a/aspnetcore/grpc/client.md b/aspnetcore/grpc/client.md index ab01248a276d..5109cedfcb4e 100644 --- a/aspnetcore/grpc/client.md +++ b/aspnetcore/grpc/client.md @@ -4,7 +4,7 @@ author: jamesnk description: Learn how to call gRPC services with the .NET gRPC client. monikerRange: '>= aspnetcore-3.0' ms.author: wpickett -ms.date: 6/5/2024 +ms.date: 01/08/2025 uid: grpc/client --- # Call gRPC services with the .NET client @@ -62,9 +62,6 @@ Channel and client performance and usage: `GrpcChannel.ForAddress` isn't the only option for creating a gRPC client. If calling gRPC services from an ASP.NET Core app, consider [gRPC client factory integration](xref:grpc/clientfactory). gRPC integration with `HttpClientFactory` offers a centralized alternative to creating gRPC clients. -> [!NOTE] -> Calling gRPC over HTTP/2 with `Grpc.Net.Client` is currently not supported on Xamarin. We are working to improve HTTP/2 support in a future Xamarin release. [Grpc.Core](https://www.nuget.org/packages/Grpc.Core) and [gRPC-Web](xref:grpc/browser) are viable alternatives that work today. - ## Make gRPC calls A gRPC call is initiated by calling a method on the client. The gRPC client will handle message serialization and addressing the gRPC call to the correct service. diff --git a/aspnetcore/grpc/netstandard.md b/aspnetcore/grpc/netstandard.md index d3125eba3efc..6532064b0bf8 100644 --- a/aspnetcore/grpc/netstandard.md +++ b/aspnetcore/grpc/netstandard.md @@ -4,7 +4,7 @@ author: jamesnk description: Learn how to use the .NET gRPC client in apps and libraries that support .NET Standard 2.0. monikerRange: '>= aspnetcore-3.0' ms.author: wpickett -ms.date: 3/11/2021 +ms.date: 01/08/2025 uid: grpc/netstandard --- # Use gRPC client with .NET Standard 2.0 @@ -22,8 +22,6 @@ The following .NET implementations (or later) support [Grpc.Net.Client](https:// * .NET Core 2.1 * .NET Framework 4.6.1 * Mono 5.4 -* Xamarin.iOS 10.14 -* Xamarin.Android 8.0 * Universal Windows Platform 10.0.16299 * Unity 2018.1 @@ -35,7 +33,7 @@ An HTTP provider must be configured using `GrpcChannelOptions.HttpHandler`. If a > `System.PlatformNotSupportedException`: gRPC requires extra configuration to successfully make RPC calls on .NET implementations that don't have support for gRPC over HTTP/2. An HTTP provider must be specified using `GrpcChannelOptions.HttpHandler`. The configured HTTP provider must either support HTTP/2 or be configured to use gRPC-Web. -.NET implementations that don't support HTTP/2, such as UWP, Xamarin, and Unity, can use gRPC-Web as an alternative. +.NET implementations that don't support HTTP/2, such as UWP and Unity, can use gRPC-Web as an alternative. ```csharp var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions @@ -90,9 +88,9 @@ var response = await client.SayHelloAsync(new HelloRequest { Name = ".NET" }); ## gRPC C# core-library -An alternative option for .NET Framework and Xamarin has been to use [gRPC C# core-library](https://grpc.io/docs/languages/csharp/quickstart/) to make gRPC calls. gRPC C# core-library is: +An alternative option for .NET Framework has been to use [gRPC C# core-library](https://grpc.io/docs/languages/csharp/quickstart/) to make gRPC calls. gRPC C# core-library is: -* A third party library that supports making gRPC calls over HTTP/2 on .NET Framework and Xamarin. +* A third party library that supports making gRPC calls over HTTP/2 on .NET Framework. * Not supported by Microsoft. * In maintenance mode and will be [deprecated in favour of gRPC for .NET](https://grpc.io/blog/grpc-csharp-future/). * Not recommended for new apps. diff --git a/aspnetcore/grpc/supported-platforms.md b/aspnetcore/grpc/supported-platforms.md index ac830e748a8a..4ca6bc3afb87 100644 --- a/aspnetcore/grpc/supported-platforms.md +++ b/aspnetcore/grpc/supported-platforms.md @@ -4,7 +4,7 @@ author: jamesnk description: Learn about the supported platforms for gRPC on .NET. monikerRange: '>= aspnetcore-3.0' ms.author: wpickett -ms.date: 10/27/2022 +ms.date: 01/08/2025 uid: grpc/supported-platforms --- # gRPC on .NET supported platforms @@ -89,7 +89,7 @@ For information about configuring ASP.NET Core servers to run gRPC, see [AddWindowsService](https://source.dot.net/#Microsoft.Extensions.Hosting.WindowsServices/WindowsServiceLifetimeHostBuilderExtensions.cs,f8bfb38e255ef3b6,references). When the app is running as a Windows Service, `AddWindowsService`: * Sets the host lifetime to `WindowsServiceLifetime`. * Sets the [content root](xref:fundamentals/index#content-root) to [AppContext.BaseDirectory](xref:System.AppContext.BaseDirectory). For more information, see the [Current directory and content root](#current-directory-and-content-root) section. diff --git a/aspnetcore/performance/rate-limit.md b/aspnetcore/performance/rate-limit.md index be1ad80f32f6..0e61c8b42632 100644 --- a/aspnetcore/performance/rate-limit.md +++ b/aspnetcore/performance/rate-limit.md @@ -190,7 +190,7 @@ The following samples aren't meant for production code but are examples on how t The following sample: -* Creates a [RateLimiterOptions.OnRejected](xref:Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.OnRejected) callback that is called when a request exceeds the specified limit. `retryAfter` can be used with the [`TokenBucketRateLimiter`](https://source.dot.net/#System.Threading.RateLimiting/System/Threading/RateLimiting/TokenBucketRateLimiter.cs), [`FixedWindowLimiter`](https://source.dot.net/#System.Threading.RateLimiting/System/Threading/RateLimiting/FixedWindowRateLimiter.cs), and [`SlidingWindowLimiter`](https://source.dot.net/#System.Threading.RateLimiting/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs) because these algorithms are able to estimate when more permits will be added. The `ConcurrencyLimiter` has no way of calculating when permits will be available. +* Creates a [RateLimiterOptions.OnRejected](xref:Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.OnRejected) callback that is called when a request exceeds the specified limit. `retryAfter` can be used with the [TokenBucketRateLimiter](/dotnet/api/system.threading.ratelimiting.tokenbucketratelimiter), [FixedWindowLimiter](/dotnet/api/microsoft.aspnetcore.ratelimiting.ratelimiteroptionsextensions.addfixedwindowlimiter), and [SlidingWindowLimiter](/dotnet/api/microsoft.aspnetcore.ratelimiting.ratelimiteroptionsextensions.addslidingwindowlimiter) because these algorithms are able to estimate when more permits will be added. The `ConcurrencyLimiter` has no way of calculating when permits will be available. * Adds the following limiters: * A `SampleRateLimiterPolicy` which implements the `IRateLimiterPolicy` interface. The `SampleRateLimiterPolicy` class is shown later in this article. diff --git a/aspnetcore/release-notes/aspnetcore-7.0.md b/aspnetcore/release-notes/aspnetcore-7.0.md index 5fb0c25c7eb7..852fdb076ae7 100644 --- a/aspnetcore/release-notes/aspnetcore-7.0.md +++ b/aspnetcore/release-notes/aspnetcore-7.0.md @@ -605,7 +605,7 @@ In .NET 7, Kestrel's memory pool is partitioned the same way as its I/O queue, w ### `ServerReady` event to measure startup time -Apps using [EventSource](/dotnet/api/system.diagnostics.tracing.eventsource) can measure the startup time to understand and optimize startup performance. The new [`ServerReady`](https://source.dot.net/#Microsoft.AspNetCore.Hosting/Internal/HostingEventSource.cs,76) event in represents the point where the server is ready to respond to requests. +Apps using [EventSource](/dotnet/api/system.diagnostics.tracing.eventsource) can measure the startup time to understand and optimize startup performance. The new [`ServerReady`](https://source.dot.net/#Microsoft.AspNetCore.Hosting/Internal/HostingEventSource.cs,76) event in represents the point where the server is ready to respond to requests. ## Server diff --git a/aspnetcore/release-notes/aspnetcore-8.0.md b/aspnetcore/release-notes/aspnetcore-8.0.md index cb471bae91df..c83036f14efe 100644 --- a/aspnetcore/release-notes/aspnetcore-8.0.md +++ b/aspnetcore/release-notes/aspnetcore-8.0.md @@ -560,11 +560,11 @@ This release adds a middleware for validating antiforgery tokens, which are used The antiforgery middleware: * Does ***not*** short-circuit the execution of the rest of the request pipeline. -* Sets the [IAntiforgeryValidationFeature](https://source.dot.net/#Microsoft.AspNetCore.Http.Features/IAntiforgeryValidationFeature.cs,33a7a0e106f11c6f) in the [HttpContext.Features](xref:Microsoft.AspNetCore.Http.HttpContext.Features) of the current request. +* Sets the [IAntiforgeryValidationFeature](https://source.dot.net/#Microsoft.AspNetCore.Http.Features/IAntiforgeryValidationFeature.cs,33a7a0e106f11c6f) in the [HttpContext.Features](xref:Microsoft.AspNetCore.Http.HttpContext.Features) of the current request. The antiforgery token is only validated if: -* The endpoint contains metadata implementing [IAntiforgeryMetadata](https://source.dot.net/#Microsoft.AspNetCore.Http.Abstractions/Metadata/IAntiforgeryMetadata.cs,5f49d4d07fc58320) where `RequiresValidation=true`. +* The endpoint contains metadata implementing [IAntiforgeryMetadata](https://source.dot.net/#Microsoft.AspNetCore.Http.Abstractions/Metadata/IAntiforgeryMetadata.cs,5f49d4d07fc58320) where `RequiresValidation=true`. * The HTTP method associated with the endpoint is a relevant [HTTP method](https://developer.mozilla.org/docs/Web/HTTP/Methods). The relevant methods are all [HTTP methods](https://developer.mozilla.org/docs/Web/HTTP/Methods) except for TRACE, OPTIONS, HEAD, and GET. * The request is associated with a valid endpoint. @@ -742,7 +742,7 @@ For more information, see and interface. +The Server Name Indication (SNI) host name is now exposed in the [HostName](https://source.dot.net/#Microsoft.AspNetCore.Connections.Abstractions/Features/ITlsHandshakeFeature.cs,29) property of the interface. SNI is part of the [TLS handshake](https://auth0.com/blog/the-tls-handshake-explained/) process. It allows clients to specify the host name they're attempting to connect to when the server hosts multiple virtual hosts or domains. To present the correct security certificate during the handshake process, the server needs to know the host name selected for each request. @@ -750,18 +750,18 @@ Normally the host name is only handled within the TLS stack and is used to selec Exposing the host name is useful for large-scale services managing thousands of SNI bindings. This feature can significantly improve debugging efficiency during customer escalations. The increased transparency allows for faster problem resolution and enhanced service reliability. -For more information, see [ITlsHandshakeFeature.HostName](https://source.dot.net/#Microsoft.AspNetCore.Connections.Abstractions/Features/ITlsHandshakeFeature.cs,30). +For more information, see [ITlsHandshakeFeature.HostName](https://source.dot.net/#Microsoft.AspNetCore.Connections.Abstractions/Features/ITlsHandshakeFeature.cs,30). ### IHttpSysRequestTimingFeature -[IHttpSysRequestTimingFeature](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/IHttpSysRequestTimingFeature.cs,3c5dc86dc837b1f4) provides detailed timing information for requests when using the [HTTP.sys server](xref:fundamentals/servers/httpsys) and [In-process hosting with IIS](xref:host-and-deploy/iis/in-process-hosting?view=aspnetcore-8.0&preserve-view=true#ihsrtf8): + [IHttpSysRequestTimingFeature](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/IHttpSysRequestTimingFeature.cs,3c5dc86dc837b1f4) provides detailed timing information for requests when using the [HTTP.sys server](xref:fundamentals/servers/httpsys) and [In-process hosting with IIS](xref:host-and-deploy/iis/in-process-hosting?view=aspnetcore-8.0&preserve-view=true#ihsrtf8): * Timestamps are obtained using [QueryPerformanceCounter](/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter). * The timestamp frequency can be obtained via [QueryPerformanceFrequency](/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency). -* The index of the timing can be cast to [HttpSysRequestTimingType](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/HttpSysRequestTimingType.cs,e62e7bcd02f8589e) to know what the timing represents. +* The index of the timing can be cast to [HttpSysRequestTimingType](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/HttpSysRequestTimingType.cs,e62e7bcd02f8589e) to know what the timing represents. * The value might be 0 if the timing isn't available for the current request. -[IHttpSysRequestTimingFeature.TryGetTimestamp](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/IHttpSysRequestTimingFeature.cs,3c5dc86dc837b1f4) retrieves the timestamp for the provided timing type: + [IHttpSysRequestTimingFeature.TryGetTimestamp](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/IHttpSysRequestTimingFeature.cs,3c5dc86dc837b1f4) retrieves the timestamp for the provided timing type: :::code language="csharp" source="~/fundamentals/request-features/samples/8.x/IHttpSysRequestTimingFeature/Program.cs" id="snippet_WithTryGetTimestamp"::: diff --git a/aspnetcore/release-notes/aspnetcore-9/includes/par.md b/aspnetcore/release-notes/aspnetcore-9/includes/par.md index c8ab78998258..4a0be285aed7 100644 --- a/aspnetcore/release-notes/aspnetcore-9/includes/par.md +++ b/aspnetcore/release-notes/aspnetcore-9/includes/par.md @@ -20,8 +20,8 @@ We'd like to thank [Joe DeCock](https://github.com/josephdecock) from [Duende So > * [Keycloak](https://www.keycloak.org/) > * [Authlete](https://www.authlete.com/developers/tutorial/oidc/) -For .NET 9, we have decided to enable PAR by default if the identity provider's discovery document advertises support for PAR, since it should provide enhanced security for providers that support it. The identity provider's discovery document is usually found at `.well-known/openid-configuration`. If this causes problems, you can disable PAR via [OpenIdConnectOptions.PushedAuthorizationBehavior](https://source.dot.net/#Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectOptions.cs,99014cc0333b1603) as follows: +For .NET 9, we have decided to enable PAR by default if the identity provider's discovery document advertises support for PAR, since it should provide enhanced security for providers that support it. The identity provider's discovery document is usually found at `.well-known/openid-configuration`. If this causes problems, you can disable PAR via [OpenIdConnectOptions.PushedAuthorizationBehavior](https://source.dot.net/#Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectOptions.cs,99014cc0333b1603) as follows: :::code language="csharp" source="~/release-notes/aspnetcore-9/samples/PAR/Program.cs" id="snippet_1" highlight="8-99"::: -To ensure that authentication only succeeds if PAR is used, use [PushedAuthorizationBehavior.Require](https://source.dot.net/#Microsoft.AspNetCore.Authentication.OpenIdConnect/PushedAuthorizationBehavior.cs,3af73de8f33b70c5) instead. This change also introduces a new [OnPushAuthorization](https://source.dot.net/#Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/OpenIdConnectEvents.cs,6a21c8f3a90753c1) event to [OpenIdConnectEvents](/dotnet/api/microsoft.aspnetcore.authentication.openidconnect.openidconnectevents) which can be used customize the pushed authorization request or handle it manually. See the [API proposal](https://github.com/dotnet/aspnetcore/issues/51686) for more details. +To ensure that authentication only succeeds if PAR is used, use [PushedAuthorizationBehavior.Require](https://source.dot.net/#Microsoft.AspNetCore.Authentication.OpenIdConnect/PushedAuthorizationBehavior.cs,3af73de8f33b70c5) instead. This change also introduces a new [OnPushAuthorization](https://source.dot.net/#Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/OpenIdConnectEvents.cs,6a21c8f3a90753c1) event to [OpenIdConnectEvents](/dotnet/api/microsoft.aspnetcore.authentication.openidconnect.openidconnectevents) which can be used customize the pushed authorization request or handle it manually. See the [API proposal](https://github.com/dotnet/aspnetcore/issues/51686) for more details. diff --git a/aspnetcore/security/anti-request-forgery.md b/aspnetcore/security/anti-request-forgery.md index 4e1a3481d0db..4d9080ab85ea 100644 --- a/aspnetcore/security/anti-request-forgery.md +++ b/aspnetcore/security/anti-request-forgery.md @@ -159,9 +159,8 @@ Calling . +This article outlines role-based authorization for ASP.NET Core MVC and Razor apps. For Blazor apps, see and . + ## Add Role services to Identity Register role-based authorization services in `Program.cs` by calling with the role type in the app's Identity configuration. The role type in the following example is `IdentityRole`: diff --git a/aspnetcore/security/gdpr.md b/aspnetcore/security/gdpr.md index 7ea6b377e798..eaa0316fa9d4 100644 --- a/aspnetcore/security/gdpr.md +++ b/aspnetcore/security/gdpr.md @@ -18,6 +18,8 @@ ASP.NET Core provides APIs and templates to help meet some of the [EU General Da * The project templates include extension points and stubbed markup that you can replace with your privacy and cookie use policy. * The `Pages/Privacy.cshtml` page or `Views/Home/Privacy.cshtml` view provides a page to detail your site's privacy policy. +For GDPR guidance that applies to Blazor apps, see . + To enable the default cookie consent feature like that found in the ASP.NET Core 2.2 templates in a current ASP.NET Core template generated app, add the following highlighted code to `Program.cs`: [!code-csharp[Main](~/security/gdpr/sample/RP6.0/WebGDPR/Program.cs?name=snippet_1&highlight=4-11,23)] @@ -64,7 +66,8 @@ For databases that don't provide built-in encryption at rest, you may be able to ## Additional resources -* [Microsoft.com/GDPR](https://www.microsoft.com/trustcenter/Privacy/GDPR) +* [Microsoft Trust Center: Safeguard individual privacy with cloud services from Microsoft: GDPR](https://www.microsoft.com/trust-center/privacy/gdpr-overview) +* [European Commission: Data protection explained](https://ec.europa.eu/info/law/law-topic/data-protection/reform/what-does-general-data-protection-regulation-gdpr-govern_en) :::moniker-end diff --git a/aspnetcore/signalr/messagepackhubprotocol.md b/aspnetcore/signalr/messagepackhubprotocol.md index 6b4e9891377d..f802445c38d1 100644 --- a/aspnetcore/signalr/messagepackhubprotocol.md +++ b/aspnetcore/signalr/messagepackhubprotocol.md @@ -5,7 +5,7 @@ description: Add MessagePack Hub Protocol to ASP.NET Core SignalR. monikerRange: '>= aspnetcore-2.1' ms.author: wpickett ms.custom: mvc -ms.date: 7/16/2021 +ms.date: 01/08/2025 uid: signalr/messagepackhubprotocol --- @@ -148,7 +148,7 @@ The MessagePack protocol doesn't provide a way to encode the `Kind` value of a ` ### MessagePack support in "ahead-of-time" compilation environment -The [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp/tree/v2.1.90) library used by the .NET client and server uses code generation to optimize serialization. As a result, it isn't supported by default on environments that use "ahead-of-time" compilation (such as Xamarin iOS or Unity). It's possible to use MessagePack in these environments by "pre-generating" the serializer/deserializer code. For more information, see [the MessagePack-CSharp documentation](https://github.com/neuecc/MessagePack-CSharp/tree/v2.1.90#aot-code-generation-to-support-unityxamarin). Once you have pre-generated the serializers, you can register them using the configuration delegate passed to `AddMessagePackProtocol`: +The [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp/tree/v2.1.90) library used by the .NET client and server uses code generation to optimize serialization. As a result, it isn't supported by default on environments that use "ahead-of-time" compilation, such as NET Multi-platform App UI (.NET MAUI) or Unity. It's possible to use MessagePack in these environments by "pre-generating" the serializer/deserializer code. For more information, see [the MessagePack-CSharp documentation](https://github.com/neuecc/MessagePack-CSharp/tree/v2.1.90#aot-code-generation-to-support-unityxamarin). Once you have pre-generated the serializers, you can register them using the configuration delegate passed to `AddMessagePackProtocol`: ```csharp services.AddSignalR() @@ -339,7 +339,7 @@ For more information on this limitation, see GitHub issue [aspnet/SignalR#2228]( ### MessagePack support in "ahead-of-time" compilation environment -The [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp/tree/v2.1.90) library used by the .NET client and server uses code generation to optimize serialization. As a result, it isn't supported by default on environments that use "ahead-of-time" compilation (such as Xamarin iOS or Unity). It's possible to use MessagePack in these environments by "pre-generating" the serializer/deserializer code. For more information, see [the MessagePack-CSharp documentation](https://github.com/neuecc/MessagePack-CSharp/tree/v2.1.90#aot-code-generation-to-support-unityxamarin). Once you have pre-generated the serializers, you can register them using the configuration delegate passed to `AddMessagePackProtocol`: +The [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp/tree/v2.1.90) library used by the .NET client and server uses code generation to optimize serialization. As a result, it isn't supported by default on environments that use "ahead-of-time" compilation, such as NET Multi-platform App UI (.NET MAUI) or Unity. It's possible to use MessagePack in these environments by "pre-generating" the serializer/deserializer code. For more information, see [the MessagePack-CSharp documentation](https://github.com/neuecc/MessagePack-CSharp/tree/v2.1.90#aot-code-generation-to-support-unityxamarin). Once you have pre-generated the serializers, you can register them using the configuration delegate passed to `AddMessagePackProtocol`: ```csharp services.AddSignalR() @@ -524,7 +524,7 @@ For more information on this limitation, see GitHub issue [aspnet/SignalR#2228]( ### MessagePack support in "ahead-of-time" compilation environment -The [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp/tree/v1.8.80) library used by the .NET client and server uses code generation to optimize serialization. As a result, it isn't supported by default on environments that use "ahead-of-time" compilation (such as Xamarin iOS or Unity). It's possible to use MessagePack in these environments by "pre-generating" the serializer/deserializer code. For more information, see [the MessagePack-CSharp documentation](https://github.com/neuecc/MessagePack-CSharp/tree/v1.8.80#pre-code-generationunityxamarin-supports). Once you have pre-generated the serializers, you can register them using the configuration delegate passed to `AddMessagePackProtocol`: +The [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp/tree/v1.8.80) library used by the .NET client and server uses code generation to optimize serialization. As a result, it isn't supported by default on environments that use "ahead-of-time" compilation, such as NET Multi-platform App UI (.NET MAUI) or Unity. It's possible to use MessagePack in these environments by "pre-generating" the serializer/deserializer code. For more information, see [the MessagePack-CSharp documentation](https://github.com/neuecc/MessagePack-CSharp/tree/v1.8.80#pre-code-generationunityxamarin-supports). Once you have pre-generated the serializers, you can register them using the configuration delegate passed to `AddMessagePackProtocol`: ```csharp services.AddSignalR() @@ -703,7 +703,7 @@ For more information on this limitation, see GitHub issue [aspnet/SignalR#2228]( ### MessagePack support in "ahead-of-time" compilation environment -The [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp/tree/v1.8.80) library used by the .NET client and server uses code generation to optimize serialization. As a result, it isn't supported by default on environments that use "ahead-of-time" compilation (such as Xamarin iOS or Unity). It's possible to use MessagePack in these environments by "pre-generating" the serializer/deserializer code. For more information, see [the MessagePack-CSharp documentation](https://github.com/neuecc/MessagePack-CSharp/tree/v1.8.80#pre-code-generationunityxamarin-supports). Once you have pre-generated the serializers, you can register them using the configuration delegate passed to `AddMessagePackProtocol`: +The [MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp/tree/v1.8.80) library used by the .NET client and server uses code generation to optimize serialization. As a result, it isn't supported by default on environments that use "ahead-of-time" compilation, such as NET Multi-platform App UI (.NET MAUI) or Unity. It's possible to use MessagePack in these environments by "pre-generating" the serializer/deserializer code. For more information, see [the MessagePack-CSharp documentation](https://github.com/neuecc/MessagePack-CSharp/tree/v1.8.80#pre-code-generationunityxamarin-supports). Once you have pre-generated the serializers, you can register them using the configuration delegate passed to `AddMessagePackProtocol`: ```csharp services.AddSignalR() diff --git a/aspnetcore/signalr/supported-platforms.md b/aspnetcore/signalr/supported-platforms.md index 6daaca451836..fad9c17e5945 100644 --- a/aspnetcore/signalr/supported-platforms.md +++ b/aspnetcore/signalr/supported-platforms.md @@ -5,7 +5,7 @@ description: Learn about the supported platforms for ASP.NET Core SignalR. monikerRange: '>= aspnetcore-3.1' ms.author: wpickett ms.custom: mvc, devx-track-js -ms.date: 09/15/2021 +ms.date: 01/09/2025 uid: signalr/supported-platforms --- # ASP.NET Core SignalR supported platforms @@ -31,7 +31,7 @@ The JavaScript client doesn't support Internet Explorer and other older browsers ## .NET client -The [.NET client](xref:signalr/dotnet-client) runs on any platform supported by ASP.NET Core. For example, [Xamarin developers can use SignalR](https://github.com/aspnet/Announcements/issues/305) for building Android apps using Xamarin.Android 8.4.0.1 and later and iOS apps using Xamarin.iOS 11.14.0.4 and later. +The [.NET client](xref:signalr/dotnet-client) runs on any platform supported by ASP.NET Core. For example, [.NET Multi-platform App UI (.NET MAUI) developers can use SignalR](https://github.com/aspnet/Announcements/issues/305) for building Android and iOS apps. If the server runs IIS, the WebSockets transport requires IIS 8.0 or later on Windows Server 2012 or later. Other transports are supported on all platforms. diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 7325831f1ee7..f9baa66412f1 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -624,6 +624,8 @@ items: uid: blazor/security/qrcodes-for-authenticator-apps - name: Content Security Policy uid: blazor/security/content-security-policy + - name: EU General Data Protection Regulation (GDPR) support + uid: blazor/security/gdpr - name: Server-side and Blazor Web App additional scenarios uid: blazor/security/additional-scenarios - name: State management diff --git a/aspnetcore/tutorials/publish-to-azure-api-management-using-vs.md b/aspnetcore/tutorials/publish-to-azure-api-management-using-vs.md index 5c3c79e9dcbe..b88841922b0b 100644 --- a/aspnetcore/tutorials/publish-to-azure-api-management-using-vs.md +++ b/aspnetcore/tutorials/publish-to-azure-api-management-using-vs.md @@ -129,7 +129,7 @@ Complete the following steps to publish the ASP.NET Core web API to Azure API Ma Notice the name of the API is named *WeatherAPI*; however, we would like to call it *Weather Forecasts*. Complete the following steps to update the name: -1. Add the following to `Program.cs` immediately after `servies.AddSwaggerGen();` +1. Add the following to `Program.cs` immediately after `services.AddSwaggerGen();` ```csharp builder.Services.ConfigureSwaggerGen(setup => diff --git a/aspnetcore/whats-new/index.yml b/aspnetcore/whats-new/index.yml index b14e779b40f7..49c551527f09 100644 --- a/aspnetcore/whats-new/index.yml +++ b/aspnetcore/whats-new/index.yml @@ -51,8 +51,8 @@ landingContent: linkLists: - linkListType: whats-new links: - - text: Xamarin docs updates - url: /xamarin/whats-new/ + - text: .NET Multi-platform App UI (.NET MAUI) docs updates + url: /dotnet/maui/whats-new/ - text: .NET Core release notes url: https://github.com/dotnet/core/blob/main/release-notes/README.md - text: ASP.NET Core release notes