diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 60b537d46395..626e236c38d4 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1649,10 +1649,30 @@ "redirect_url": "/aspnet/core/fundamentals/error-handling-api", "redirect_document_id": false }, - { + { "source_path": "aspnetcore/fundamentals/map-static-files.md", "redirect_url": "/aspnet/core/fundamentals/static-files", "redirect_document_id": false + }, + { + "source_path": "aspnetcore/migration/60-70.md", + "redirect_url": "/aspnet/core/migration/60-to-70", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/migration/70-80.md", + "redirect_url": "/aspnet/core/migration/70-to-80", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/migration/80-90.md", + "redirect_url": "/aspnet/core/migration/80-to-90", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/migration/20_21.md", + "redirect_url": "/aspnet/core/migration/20-to-21", + "redirect_document_id": false } ] } diff --git a/aspnetcore/blazor/call-web-api.md b/aspnetcore/blazor/call-web-api.md index a8698f9355b0..d8c899decc09 100644 --- a/aspnetcore/blazor/call-web-api.md +++ b/aspnetcore/blazor/call-web-api.md @@ -358,7 +358,24 @@ The solution includes a demonstration of obtaining weather data securely via an ## Disposal of `HttpRequestMessage`, `HttpResponseMessage`, and `HttpClient` -An without a body doesn't require explicit disposal with a [`using` declaration (C# 8 or later)](/dotnet/csharp/language-reference/proposals/csharp-8.0/using) or a [`using` block (all C# releases)](/dotnet/csharp/language-reference/keywords/using), but we recommend disposing with every use for the following reasons: +An without a body doesn't require explicit disposal. However, you can dispose of it with either of the following patterns: + +* `using` declaration (C# 8 or later): + + ```csharp + using var request = new HttpRequestMessage(...); + ``` + +* [`using` block (all C# releases)](/dotnet/csharp/language-reference/keywords/using): + + ```csharp + using (var request = new HttpRequestMessage(...)) + { + ... + } + ``` + +We recommend disposing of every with every use for the following reasons: * To gain a performance improvement by avoiding finalizers. * It hardens the code for the future in case a request body is ever added to an that didn't initially have one. diff --git a/aspnetcore/blazor/components/quickgrid.md b/aspnetcore/blazor/components/quickgrid.md index 59b999af5aae..903a92cfa08b 100644 --- a/aspnetcore/blazor/components/quickgrid.md +++ b/aspnetcore/blazor/components/quickgrid.md @@ -127,7 +127,7 @@ Set the `QuickGrid` component's ``` - To provide a UI for pagination, add a [`Paginator` component](xref:Microsoft.AspNetCore.Components.QuickGrid.Paginator) above or below the `QuickGrid` component. Set the to `pagination`: diff --git a/aspnetcore/blazor/components/rendering.md b/aspnetcore/blazor/components/rendering.md index 0a0f331eaf71..57a738e49589 100644 --- a/aspnetcore/blazor/components/rendering.md +++ b/aspnetcore/blazor/components/rendering.md @@ -349,7 +349,4 @@ The state manager approach is similar to the earlier case with - -A loading progress indicator isn't present in an app created from the Blazor Web App project template. A new loading progress indicator feature is planned for a future release of .NET. In the meantime, an app can adopt custom code to create a loading progress indicator. For more information, see . +An app can adopt custom code to create a loading progress indicator. For more information, see . diff --git a/aspnetcore/blazor/file-uploads.md b/aspnetcore/blazor/file-uploads.md index afc764734c95..5faa61f98d4a 100644 --- a/aspnetcore/blazor/file-uploads.md +++ b/aspnetcore/blazor/file-uploads.md @@ -98,17 +98,6 @@ await blobContainerClient.UploadBlobAsync( A component that receives an image file can call the convenience method on the file to resize the image data within the browser's JavaScript runtime before the image is streamed into the app. Use cases for calling are most appropriate for Blazor WebAssembly apps. -:::moniker range="< aspnetcore-9.0" - - - -## Autofac Inversion of Control (IoC) container users - -If you're using the [Autofac Inversion of Control (IoC) container](https://autofac.org/) instead of the built-in ASP.NET Core dependency injection container, set to `true` in the [server-side circuit handler hub options](xref:blazor/fundamentals/signalr#server-side-circuit-handler-options). For more information, see [FileUpload: Did not receive any data in the allotted time (`dotnet/aspnetcore` #38842)](https://github.com/dotnet/aspnetcore/issues/38842#issuecomment-1342540950). - -:::moniker-end - ## File size read and upload limits :::moniker range=">= aspnetcore-9.0" @@ -293,7 +282,7 @@ public class UploadResult A security best practice for production apps is to avoid sending error messages to clients that might reveal sensitive information about an app, server, or network. Providing detailed error messages can aid a malicious user in devising attacks on an app, server, or network. The example code in this section only sends back an error code number (`int`) for display by the component client-side if a server-side error occurs. If a user requires assistance with a file upload, they provide the error code to support personnel for support ticket resolution without ever knowing the exact cause of the error. - @@ -302,9 +291,9 @@ The following `LazyBrowserFileStream` class defines a custom stream type that la `LazyBrowserFileStream.cs`: - + - + :::moniker range=">= aspnetcore-8.0" @@ -369,7 +358,7 @@ The following `FileUpload2` component: :::moniker-end - + :::moniker range=">= aspnetcore-8.0" @@ -1297,7 +1286,7 @@ Possible causes: * Not reading the stream to completion. This isn't a framework issue. Trap the exception and investigate it further in your local environment/network. - diff --git a/aspnetcore/blazor/forms/index.md b/aspnetcore/blazor/forms/index.md index c9e1964d6388..b1b6bce6e52d 100644 --- a/aspnetcore/blazor/forms/index.md +++ b/aspnetcore/blazor/forms/index.md @@ -448,9 +448,9 @@ jQuery validation isn't supported in Razor components. We recommend any of the f * Use native HTML validation attributes (see [Client-side form validation](https://developer.mozilla.org/docs/Learn/Forms/Form_validation)). * Adopt a third-party validation JavaScript library. - + -For statically-rendered forms on the server, a new mechanism for client-side validation is under consideration for .NET 10 in late 2025. For more information, see [Create server rendered forms with client validation using Blazor without a circuit (`dotnet/aspnetcore` #51040)](https://github.com/dotnet/aspnetcore/issues/51040). +For statically-rendered forms on the server, a new mechanism for client-side validation is under consideration. For more information, see [Create server rendered forms with client validation using Blazor without a circuit (`dotnet/aspnetcore` #51040)](https://github.com/dotnet/aspnetcore/issues/51040). ## Additional resources diff --git a/aspnetcore/blazor/fundamentals/dependency-injection.md b/aspnetcore/blazor/fundamentals/dependency-injection.md index 02934ffdb378..53fe7304cb83 100644 --- a/aspnetcore/blazor/fundamentals/dependency-injection.md +++ b/aspnetcore/blazor/fundamentals/dependency-injection.md @@ -355,8 +355,6 @@ public IMyService MyService { get; set; } ## Utility base component classes to manage a DI scope - - In non-Blazor ASP.NET Core apps, scoped and transient services are typically scoped to the current request. After the request completes, scoped and transient services are disposed by the DI system. In interactive server-side Blazor apps, the DI scope lasts for the duration of the circuit (the SignalR connection between the client and server), which can result in scoped and disposable transient services living much longer than the lifetime of a single component. Therefore, don't directly inject a scoped service into a component if you intend the service lifetime to match the lifetime of the component. Transient services injected into a component that don't implement are garbage collected when the component is disposed. However, injected transient services *that implement * are maintained by the DI container for the lifetime of the circuit, which prevents service garbage collection when the component is disposed and results in a memory leak. An alternative approach for scoped services based on the type is described later in this section, and disposable transient services shouldn't be used at all. For more information, see [Design for solving transient disposables on Blazor Server (`dotnet/aspnetcore` #26676)](https://github.com/dotnet/aspnetcore/issues/26676). diff --git a/aspnetcore/blazor/fundamentals/environments.md b/aspnetcore/blazor/fundamentals/environments.md index c20b4c1dc590..108613998fb5 100644 --- a/aspnetcore/blazor/fundamentals/environments.md +++ b/aspnetcore/blazor/fundamentals/environments.md @@ -15,10 +15,6 @@ uid: blazor/fundamentals/environments This article explains how to configure and read the [environment](xref:fundamentals/environments) in a Blazor app. When running an app locally, the environment defaults to `Development`. When the app is published, the environment defaults to `Production`. - - We recommend the following conventions: diff --git a/aspnetcore/blazor/fundamentals/signalr.md b/aspnetcore/blazor/fundamentals/signalr.md index 03400de91b20..330bb1437ea4 100644 --- a/aspnetcore/blazor/fundamentals/signalr.md +++ b/aspnetcore/blazor/fundamentals/signalr.md @@ -316,7 +316,7 @@ app.MapBlazorHub(options => }); ``` - Configuring the hub used by with fails with an : diff --git a/aspnetcore/blazor/host-and-deploy/configure-trimmer.md b/aspnetcore/blazor/host-and-deploy/configure-trimmer.md index 4a7ece7169e5..da350e8df99e 100644 --- a/aspnetcore/blazor/host-and-deploy/configure-trimmer.md +++ b/aspnetcore/blazor/host-and-deploy/configure-trimmer.md @@ -18,7 +18,7 @@ Blazor WebAssembly performs [Intermediate Language (IL)](/dotnet/standard/glossa ## Default trimmer granularity - - * Using the .NET 9 SDK * Targeting .NET 9 requires `wasm-tools`. * Targeting .NET 8 requires `wasm-tools-net8`. diff --git a/aspnetcore/diagnostics/asp0026.md b/aspnetcore/diagnostics/asp0026.md index bf7e7c51ed18..ddca3fe8ad8c 100644 --- a/aspnetcore/diagnostics/asp0026.md +++ b/aspnetcore/diagnostics/asp0026.md @@ -1,10 +1,11 @@ --- title: "ASP0026: Analyzer to warn when [Authorize] is overridden by [AllowAnonymous] from 'farther away'" -ms.date: 03/27/2025 -description: "Learn about analysis rule ASP0026: [Authorize] is overridden by [AllowAnonymous] from 'farther away'" +ai-usage: ai-assisted author: tdykstra +description: "Learn about analysis rule ASP0026: [Authorize] is overridden by [AllowAnonymous] from 'farther away'" monikerRange: '>= aspnetcore-9.0' ms.author: tdykstra +ms.date: 11/06/2025 uid: diagnostics/asp0026 --- # ASP0026: `[Authorize]` is overridden by `[AllowAnonymous]` from "farther away" @@ -19,6 +20,9 @@ uid: diagnostics/asp0026 It seems intuitive that an `[Authorize]` attribute placed "closer" to an MVC action than an `[AllowAnonymous]` attribute would override the `[AllowAnonymous]` attribute and force authorization. However, this is not necessarily the case. What does matter is the relative order of the attributes. +> [!NOTE] +> The `[AllowAnonymous]` attribute doesn't disable authentication entirely. When credentials are sent to an endpoint with `[AllowAnonymous]`, the endpoint still authenticates those credentials and establishes the user's identity. The `[AllowAnonymous]` attribute only means that authentication is **not required**—the endpoint will run as anonymous only when no credentials are provided. This behavior can be useful for endpoints that need to work for both authenticated and anonymous users. + The following code shows examples where a closer `[Authorize]` attribute gets overridden by an `[AllowAnonymous]` attribute that is farther away. ```csharp @@ -58,7 +62,12 @@ public class MyControllerMultiple : ControllerBase ## Rule description -Warning that an `[Authorize]` attribute is overridden by an `[AllowAnonymous]` attribute from "farther away." +This warning indicates that an `[Authorize]` attribute is overridden by an `[AllowAnonymous]` attribute from "farther away." When `[AllowAnonymous]` takes precedence, the endpoint doesn't require authentication but still accepts and processes credentials if they're provided. This means: + +- If a request includes authentication credentials, the endpoint authenticates the user and makes their identity available. +- If a request doesn't include credentials, the endpoint allows anonymous access. + +This behavior might unintentionally expose endpoints that were meant to require authentication. ## How to fix violations @@ -70,8 +79,10 @@ public class MyController { // This produces no warning because the second, "closer" [AllowAnonymous] // clarifies that [Authorize] is intentionally overridden. - // Specifying AuthenticationSchemes can still be useful - // for endpoints that allow but don't require authenticated users. + // Specifying AuthenticationSchemes can be useful for endpoints that + // allow but don't require authenticated users. When credentials are sent, + // they will be authenticated; when no credentials are sent, the endpoint + // allows anonymous access. [Authorize(AuthenticationSchemes = "Cookies")] [AllowAnonymous] public IActionResult Privacy() => null; diff --git a/aspnetcore/host-and-deploy/linux-nginx.md b/aspnetcore/host-and-deploy/linux-nginx.md index a53206a24a31..fc4a05efa46b 100644 --- a/aspnetcore/host-and-deploy/linux-nginx.md +++ b/aspnetcore/host-and-deploy/linux-nginx.md @@ -1,11 +1,12 @@ --- title: Host ASP.NET Core on Linux with Nginx +ai-usage: ai-assisted author: tdykstra description: Learn how to set up Nginx as a reverse proxy on Ubuntu, RHEL and SUSE to forward HTTP traffic to an ASP.NET Core web app running on Kestrel. monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra ms.custom: mvc, engagement-fy23, linux-related-content, sfi-ropc-nochange -ms.date: 5/8/2023 +ms.date: 11/10/2025 uid: host-and-deploy/linux-nginx --- # Host ASP.NET Core on Linux with Nginx @@ -123,7 +124,7 @@ For more information, see . # [Ubuntu](#tab/linux-ubuntu) -Use `apt-get` to install Nginx. The installer creates a [`systemd`](https://systemd.io/) init script that runs Nginx as daemon on system startup. Follow the installation instructions for Ubuntu at [Nginx: Official Debian/Ubuntu packages](https://www.nginx.com/resources/wiki/start/topics/tutorials/install/#official-debian-ubuntu-packages). +Use `apt-get` to install Nginx. The installer creates a [`systemd`](https://systemd.io/) init script that runs Nginx as daemon on system startup. Follow the installation instructions for Ubuntu at [Nginx: Linux packages - Ubuntu](https://nginx.org/en/linux_packages.html#Ubuntu). # [Red Hat Enterprise Linux](#tab/linux-rhel) @@ -546,7 +547,7 @@ After upgrading the shared framework on the server, restart the ASP.NET Core app ## Additional resources * [Prerequisites for .NET on Linux](/dotnet/core/linux-prerequisites) -* [Nginx: Binary Releases: Official Debian/Ubuntu packages](https://www.nginx.com/resources/wiki/start/topics/tutorials/install/#official-debian-ubuntu-packages) +* [Nginx: Linux packages - Ubuntu](https://nginx.org/en/linux_packages.html#Ubuntu) * * * [NGINX: Using the Forwarded header](https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/) diff --git a/aspnetcore/migration/20_21.md b/aspnetcore/migration/20-to-21.md similarity index 99% rename from aspnetcore/migration/20_21.md rename to aspnetcore/migration/20-to-21.md index 2d8cf4a29001..a1ba0bc356e7 100644 --- a/aspnetcore/migration/20_21.md +++ b/aspnetcore/migration/20-to-21.md @@ -5,7 +5,7 @@ description: This article covers the basics of migrating an ASP.NET Core 2.0 app ms.author: wpickett ms.custom: mvc ms.date: 06/09/2019 -uid: migration/20_21 +uid: migration/20-to-21 --- # Migrate from ASP.NET Core 2.0 to 2.1 diff --git a/aspnetcore/migration/60-70.md b/aspnetcore/migration/60-to-70.md similarity index 100% rename from aspnetcore/migration/60-70.md rename to aspnetcore/migration/60-to-70.md diff --git a/aspnetcore/migration/70-80.md b/aspnetcore/migration/70-to-80.md similarity index 100% rename from aspnetcore/migration/70-80.md rename to aspnetcore/migration/70-to-80.md diff --git a/aspnetcore/migration/80-90.md b/aspnetcore/migration/80-to-90.md similarity index 100% rename from aspnetcore/migration/80-90.md rename to aspnetcore/migration/80-to-90.md diff --git a/aspnetcore/migration/90-to-100.md b/aspnetcore/migration/90-to-100.md index 5e47dad2d25b..8d335052cda2 100644 --- a/aspnetcore/migration/90-to-100.md +++ b/aspnetcore/migration/90-to-100.md @@ -3,7 +3,7 @@ title: Migrate from ASP.NET Core in .NET 9 to ASP.NET Core in .NET 10 author: wadepickett description: Learn how to migrate an ASP.NET Core in .NET 9 to ASP.NET Core in .NET 10. ms.author: wpickett -ms.date: 8/14/2025 +ms.date: 11/10/2025 uid: migration/90-to-100 --- # Migrate from ASP.NET Core in .NET 9 to ASP.NET Core in .NET 10 diff --git a/aspnetcore/migration/90-to-100/includes/blazor.md b/aspnetcore/migration/90-to-100/includes/blazor.md index bcea105f933a..ae34b21d05ed 100644 --- a/aspnetcore/migration/90-to-100/includes/blazor.md +++ b/aspnetcore/migration/90-to-100/includes/blazor.md @@ -1,4 +1,48 @@ -Complete migration coverage for Blazor apps is scheduled for September and October of 2025. +### Blazor release notes + +For new feature coverage, see . + +### Set the Blazor WebAssembly environment with the `WasmApplicationEnvironmentName` MSBuild property + +*This section only applies to standalone Blazor WebAssembly apps.* + +The `Properties/launchSettings.json` file is no longer used to control the environment in standalone Blazor WebAssembly apps. + +Set the environment with the `` property in the app's project file (`.csproj`). + +The following example sets the app's environment to `Staging`: + +```xml +Staging +``` + +The default environments are: + +* `Development` for build. +* `Production` for publish. + +### Boot configuration file inlined + +Blazor's boot configuration, which prior to the release of .NET 10 existed in a file named `blazor.boot.json`, has been inlined into the `dotnet.js` script. This only affects developers who are interacting directly with the `blazor.boot.json` file, such as when developers are: + +* Checking file integrity for published assets with the troubleshoot integrity PowerShell script per the guidance in . +* Changing the file name extension of DLL files when not using the default Webcil file format per the guidance in . + +Currently, there's no documented replacement strategy for the preceding approaches. If you require either of the preceding strategies, open a new documentation issue describing your scenario using the **Open a documentation issue** link at the bottom of either article. + +### Declarative model for persisting state from components and services + +In prior Blazor releases, persisting component state during prerendering using the service involved a significant amount of code. Starting with .NET 10, you can declaratively specify state to persist from components and services using the `[PersistentState]` attribute. For more information, see . + +### Custom Blazor cache and `BlazorCacheBootResources` MSBuild property removed + +Now that all Blazor client-side files are fingerprinted and cached by the browser, Blazor's custom caching mechanism and the `BlazorCacheBootResources` MSBuild property are no longer available. If the client-side project's project file contains the MSBuild property, remove the property, as it no longer has any effect: + +```diff +- ... +``` + +For more information, see . ### Adopt passkey user authentication in an existing Blazor Web App diff --git a/aspnetcore/migration/fx-to-core/areas/hosting.md b/aspnetcore/migration/fx-to-core/areas/hosting.md new file mode 100644 index 000000000000..064745c9a48b --- /dev/null +++ b/aspnetcore/migration/fx-to-core/areas/hosting.md @@ -0,0 +1,274 @@ +--- +title: .NET Generic Host in ASP.NET Framework +description: How to take advantage of the .NET generic hosting pattern in ASP.NET Framework applications +ai-usage: ai-assisted +author: twsouthwick +ms.author: tasou +monikerRange: '>= aspnetcore-6.0' +ms.date: 11/10/2025 +ms.topic: article +uid: migration/fx-to-core/areas/hosting +--- + +# ASP.NET Framework HttpApplicationHost + +The System.Web adapters library enables ASP.NET Framework applications to use the .NET generic host pattern, bringing modern application infrastructure capabilities to traditional ASP.NET Framework projects. This approach provides access to dependency injection, logging, configuration, and other services that are standard in modern .NET applications, while maintaining compatibility with existing ASP.NET Framework code. + +## Why use the host pattern + +Adopting the generic host pattern in ASP.NET Framework applications provides several key benefits: + +* **Dependency Injection**: Access to the built-in dependency injection container used in modern .NET, enabling better testability, maintainability, and separation of concerns +* **Unified Logging**: Integration with `Microsoft.Extensions.Logging`, providing a consistent logging experience across your application and access to various logging providers +* **Modern Configuration**: Use the configuration system from modern .NET, including support for JSON files, environment variables, user secrets, and other configuration sources +* **Migration Path**: Prepare your codebase for migration to ASP.NET Core by adopting modern patterns incrementally while maintaining your existing ASP.NET Framework application +* **Service Defaults**: Leverage service defaults and standardized application infrastructure patterns commonly used in modern .NET applications + +## Setting up the generic host + +To configure the generic host pattern in an ASP.NET Framework application, register the host in the `Application_Start` method of your `Global.asax.cs` file: + +```csharp +using System.Web; +using Microsoft.AspNetCore.SystemWebAdapters.Hosting; +using Microsoft.Extensions.Hosting; + +namespace MvcApp +{ + public class MvcApplication : HttpApplication + { + protected void Application_Start() + { + HttpApplicationHost.RegisterHost(builder => + { + builder.AddServiceDefaults(); + builder.AddSystemWebDependencyInjection(); + builder.AddSystemWebAdapters(); + }); + + // Existing ASP.NET Framework configuration + AreaRegistration.RegisterAllAreas(); + GlobalConfiguration.Configure(WebApiConfig.Register); + FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); + RouteConfig.RegisterRoutes(RouteTable.Routes); + BundleConfig.RegisterBundles(BundleTable.Bundles); + } + } +} +``` + +The `HttpApplicationHost.RegisterHost` method configures a generic host that runs alongside your ASP.NET Framework application. The host builder accepts configuration through extension methods that add various capabilities. + +## Dependency injection + +> [!NOTE] +> This currently is in a preview version of the adapters. You must be using 2.2.0-preview1.25554.5 or greater to use this feature. + +The `AddSystemWebDependencyInjection` method enables dependency injection throughout your ASP.NET Framework application. Services registered with the generic host's service collection become available to controllers, handlers, and other components. + +This extension method is an internal method that will be source generated depending on what you have referenced. The following frameworks are supported: + +- WebForms and handlers using the +- ASP.NET MVC using +- ASP.NET WebApi using [DependencyResolver](/previous-versions/aspnet/hh969140(v=vs.108)) + +### Registering services + +Register services with the dependency injection container by accessing the `Services` property on the host builder: + +```csharp +HttpApplicationHost.RegisterHost(builder => +{ + builder.AddSystemWebDependencyInjection(); + builder.AddSystemWebAdapters(); + + builder.Services.AddScoped(); + builder.Services.AddSingleton(); +}); +``` + +For details on how to customize the dependency injection system, including replacing the service container, see the full documentation: . + +If you are currently overriding the dependency injection hooks in the ASP.NET Framework, you will need to update to the current pattern for your dependency injection and remove the existing integrations for WebForms/MVC4/WebAPI. + +### Consuming services + +Once registered, services can be injected into MVC controllers, Web API controllers, and other components that support dependency injection: + +```csharp +public class HomeController : Controller +{ + private readonly IMyService _myService; + private readonly ILogger _logger; + + public HomeController(IMyService myService, ILogger logger) + { + _myService = myService; + _logger = logger; + } + + public ActionResult Index() + { + _logger.LogInformation("Loading home page"); + var data = _myService.GetData(); + return View(data); + } +} +``` + +Within a request, a scoped set of services may be retrieved by a special extension method: + +```csharp +var myService = HttpContext.Current.GetRequestServices().GetService(typeof(ISomeType)); +``` + +> [!WARNING] +> implements so you may see extension methods to get services from it. However, it is not implemented in a way to retrieve any useful services from a registered container. You will see an error if you attempt to use it and you should instead use the `GetRequestServices()` extension method first. + +## Logging + +The generic host integrates `Microsoft.Extensions.Logging`, providing a modern logging infrastructure for your ASP.NET Framework application. + +### Using loggers + +Inject `ILogger` into your classes to log messages: + +```csharp +public class OrderService : IOrderService +{ + private readonly ILogger _logger; + + public OrderService(ILogger logger) + { + _logger = logger; + } + + public void ProcessOrder(int orderId) + { + _logger.LogInformation("Processing order {OrderId}", orderId); + + try + { + // Process order logic + _logger.LogDebug("Order {OrderId} processed successfully", orderId); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error processing order {OrderId}", orderId); + throw; + } + } +} +``` + +For details on customizing and using logging, including integrating with your own providers, see . + +## Configuration + +The generic host supports the modern .NET configuration system, including JSON files, environment variables, and other configuration sources. By default, the `HttpApplicationHost` uses standard configuration patterns (such as `appsettings.json` and `appsettings.{Environment}.json`), and automatically includes values from and for compatibility with existing ASP.NET Framework applications. + +### Accessing configuration + +Inject `IConfiguration` to access configuration values: + +```csharp +public class EmailService : IEmailService +{ + private readonly string _smtpServer; + private readonly ILogger _logger; + + public EmailService(IConfiguration configuration, ILogger logger) + { + _smtpServer = configuration["Email:SmtpServer"]; + _logger = logger; + } + + public void SendEmail(string to, string subject, string body) + { + _logger.LogInformation("Sending email to {Recipient} via {SmtpServer}", to, _smtpServer); + // Email sending logic + } +} +``` + +For code that can't use dependency injection, use the static `AppConfiguration` helper class to access configuration values: + +```csharp +using Microsoft.AspNetCore.SystemWebAdapters; + +var configValue = AppConfiguration.GetSetting("SomeSettings"); +var connStr = AppConfiguration.GetConnectionString("connection-string-name"); +``` + +This will work on both ASP.NET Core and ASP.NET Framework applications that are referencing `Microsoft.AspNetCore.SystemWebAdapters` and will provide access to the current `IConfiguration`. + +### Using options pattern + +The options pattern provides strongly-typed access to configuration sections: + +```csharp +public class EmailSettings +{ + public string SmtpServer { get; set; } + public int Port { get; set; } + public string Username { get; set; } +} + +// Register options +HttpApplicationHost.RegisterHost(builder => +{ + builder.Services.Configure( + builder.Configuration.GetSection("Email")); + + builder.AddSystemWebDependencyInjection(); + builder.AddSystemWebAdapters(); +}); + +// Consume options +public class EmailService : IEmailService +{ + private readonly EmailSettings _settings; + private readonly ILogger _logger; + + public EmailService(IOptions options, ILogger logger) + { + _settings = options.Value; + _logger = logger; + } +} +``` + +For advanced configuration scenarios, including custom configuration sources and environment-specific settings, see . + +## Migration strategies + +Completely converting to the generic host pattern may not be needed for smaller projects, but can make migration much easier for larger projects. If you have successfully converted to using this, then you can swap the `HttpApplicationHost` usage for the `WebApplication` in ASP.NET Core. + +While migrating to this setup, small incremental changes will help ensure a successful conversion. A recommended order to use for migrating here would be the following: + +1. Add an initial host registration: + ```csharp + HttpApplicationHost.RegisterHost(builder => + { + }); + ``` +1. Update to use Microsoft Extensions dependency injection: + ```csharp + HttpApplicationHost.RegisterHost(builder => + { + builder.AddSystemWebDependencyInjection(); + }); + ``` + + While doing this, you may need to adapt your current containers according to their own documentation for integrating in with the Microsoft Extensions dependency injection +1. Identify your logging system and integrate it into the Microsoft Extension logging infrastructure. Decide if you want to continue using the logger types from your existing system or migrating to the `ILogger<>` types the HttpApplicationHost will provide. +1. Replace all calls to and with the new equivalent `AppConfiguration` call. You must be referencing `Microsoft.AspNetCore.SystemWebAdapters` in the project where you want to do this. +1. Start using the options pattern to convert configuration into POCO that can be passed to consuming services using the integrated DI system +1. Move your settings from `web.config` to `appsettings.json` + +## Additional resources + +* +* +* +* \ No newline at end of file diff --git a/aspnetcore/migration/fx-to-core/areas/index.md b/aspnetcore/migration/fx-to-core/areas/index.md index c5523f8ee2ca..5afd1af5f10c 100644 --- a/aspnetcore/migration/fx-to-core/areas/index.md +++ b/aspnetcore/migration/fx-to-core/areas/index.md @@ -3,18 +3,20 @@ title: Complex migration scenarios - Deep dive areas description: Detailed guidance for complex ASP.NET Framework to ASP.NET Core migration scenarios author: twsouthwick ms.author: tasou -ms.date: 07/17/2025 +ms.date: 11/10/2025 uid: migration/fx-to-core/areas --- # Technology specific guidance * [Authentication](authentication.md) * [ClaimsPrincipal.Current](claimsprincipal-current.md) +* [HttpApplicationHost](hosting.md) * [HttpContext](http-context.md) * [HTTP Handlers](http-handlers.md) * [HTTP Modules](http-modules.md) * [Membership](membership.md) * [Miscellaneous](misc.md) +* [OWIN](owin.md) * [Session State](session.md) * [WebAPI](webapi.md) diff --git a/aspnetcore/migration/fx-to-core/areas/owin.md b/aspnetcore/migration/fx-to-core/areas/owin.md new file mode 100644 index 000000000000..346f05cd6735 --- /dev/null +++ b/aspnetcore/migration/fx-to-core/areas/owin.md @@ -0,0 +1,369 @@ +--- +title: OWIN integration in ASP.NET Core +description: How to use OWIN middleware in ASP.NET Core applications during migration from ASP.NET Framework +ai-usage: ai-assisted +author: twsouthwick +ms.author: tasou +monikerRange: '>= aspnetcore-6.0' +ms.date: 11/10/2025 +ms.topic: article +uid: migration/fx-to-core/areas/owin +--- + +# OWIN integration + +The `Microsoft.AspNetCore.SystemWebAdapters.Owin` library enables ASP.NET Core applications to use OWIN middleware during migration from ASP.NET Framework. This integration is valuable when migrating applications that rely on OWIN-based middleware, particularly for authentication, authorization, or custom pipeline components. + +> [!WARNING] +> When using OWIN integration, you may need to suppress build warnings for .NET Framework package dependencies. Add the following to your project file: +> ```xml +> +> $(NoWarn);NU1701 +> +> ``` +> Running .NET Framework code on .NET Core is supported as long as the APIs used exist and have the same behavior. It is recommended to use this as part of the migration process, but to not stay in this state for too long. +> +> Some packages will need to be manually updated to supported version if used. These include: +> * EntityFramework must be >= 6.5.1 for best support on .NET Core + +## Why use OWIN integration + +OWIN integration provides several benefits during migration: + +* **Preserve existing middleware**: Reuse OWIN middleware from your ASP.NET Framework application without immediate rewrites +* **Gradual migration**: Migrate middleware components incrementally while maintaining application functionality +* **Authentication continuity**: Maintain authentication state and share cookies between ASP.NET Framework and ASP.NET Core applications during migration +* **Familiar patterns**: Continue using OWIN APIs and patterns that your team already understands + +## Integration patterns + +The library provides three distinct integration patterns, each suited for different migration scenarios: + +1. **OWIN pipeline as main pipeline middleware**: Add OWIN middleware directly to the ASP.NET Core middleware pipeline +2. **OWIN pipeline as authentication handler**: Use OWIN middleware as an ASP.NET Core authentication handler +3. **OWIN pipeline in emulated HttpApplication events**: Run OWIN middleware within the emulated `HttpApplication` pipeline + +## OWIN pipeline as middleware + +This pattern incorporates OWIN middleware into the ASP.NET Core middleware pipeline without using emulated `HttpApplication` events. + +### When to use this pattern + +Use this approach when: + +* You want standard middleware pipeline behavior +* Your application doesn't rely on `HttpApplication` events +* You're gradually migrating OWIN middleware to ASP.NET Core patterns + +### Setup + +Add OWIN middleware to the main pipeline: + +```csharp +var builder = WebApplication.CreateBuilder(args); + +var app = builder.Build(); + +app.UseOwin(owinApp => +{ + owinApp.UseMyOwinMiddleware(); +}); + +app.UseRouting(); +app.MapControllers(); + +app.Run(); +``` + +### Access services + +Access services when configuring OWIN middleware: + +```csharp +app.UseOwin((owinApp, services) => +{ + var configuration = services.GetRequiredService(); + owinApp.UseMyOwinMiddleware(configuration); +}); +``` + +## OWIN authentication handler + +This pattern uses OWIN middleware as an ASP.NET Core authentication handler, integrating with the `AuthenticationBuilder` API. + +### When to use this pattern + +Use this approach when: + +* Migrating authentication logic from ASP.NET Framework +* Sharing authentication cookies between ASP.NET Framework and ASP.NET Core applications +* Using OWIN authentication middleware such as cookie authentication or OAuth providers +* Working with ASP.NET Framework Identity + +### Setup + +Register OWIN authentication as an ASP.NET Core authentication handler: + +```csharp +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddAuthentication() + .AddOwinAuthentication((owinApp, services) => + { + owinApp.UseCookieAuthentication(new CookieAuthenticationOptions + { + AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, + LoginPath = new PathString("/Account/Login") + }); + }); + +var app = builder.Build(); + +app.UseAuthentication(); +app.UseAuthorization(); + +// Additional middleware or endpoint mapping + +app.Run(); +``` + +### Custom authentication scheme + +Specify a custom authentication scheme name: + +```csharp +builder.Services + .AddAuthentication() + .AddOwinAuthentication("MyOwinScheme", (owinApp, services) => + { + owinApp.UseMyOwinAuthenticationMiddleware(); + }); +``` + +When no scheme name is provided, the authentication handler uses `OwinAuthenticationDefaults.AuthenticationScheme` as the default scheme. The authentication scheme name determines: + +* **Default authentication**: If set as the default scheme, it automatically authenticates requests without requiring an `[Authorize]` attribute +* **Challenge behavior**: Controls which handler responds to authentication challenges (such as redirecting to a login page) +* **Authentication selection**: Allows you to explicitly authenticate against a specific scheme using `HttpContext.AuthenticateAsync("scheme-name")` + +For applications with multiple authentication schemes, you can configure the default authentication and challenge schemes: + +```csharp +builder.Services + .AddAuthentication(options => + { + options.DefaultAuthenticateScheme = "MyOwinScheme"; + options.DefaultChallengeScheme = "MyOwinScheme"; + }) + .AddOwinAuthentication("MyOwinScheme", (owinApp, services) => + { + owinApp.UseMyOwinAuthenticationMiddleware(); + }); +``` + +For more information about authentication schemes and how they work in ASP.NET Core, see and . + +### Access OWIN authentication + +Continue using the OWIN `IAuthenticationManager` interface: + +```csharp +var authManager = HttpContext.GetOwinContext().Authentication; + +authManager.SignIn(identity); +authManager.SignOut(); +``` + +### + +If code is expecting to use , then see for options to enable setting that property. + +## Migrating ASP.NET Framework Identity + +A common migration scenario involves ASP.NET Framework Identity with OWIN cookie authentication. This example shows how to maintain compatibility during migration. + +### Configure data protection + +Configure data protection to match ASP.NET Framework settings for cookie sharing: + +```csharp +var builder = WebApplication.CreateBuilder(args); + +var sharedApplicationName = "CommonMvcAppName"; +builder.Services.AddDataProtection() + .PersistKeysToFileSystem(new DirectoryInfo(Path.Combine(Path.GetTempPath(), "sharedkeys", sharedApplicationName))) + .SetApplicationName(sharedApplicationName); +``` + +### Configure OWIN authentication + +Set up OWIN authentication with Identity services: + +```csharp +builder.Services + .AddAuthentication() + .AddOwinAuthentication("AppAuthenticationScheme", (app, services) => + { + app.CreatePerOwinContext(ApplicationDbContext.Create); + app.CreatePerOwinContext(ApplicationUserManager.Create); + app.CreatePerOwinContext(ApplicationSignInManager.Create); + + var dataProtector = services.GetDataProtector( + "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", + "AppAuthenticationScheme", + "v2"); + + app.UseCookieAuthentication(new CookieAuthenticationOptions + { + AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, + LoginPath = new PathString("/Account/Login"), + Provider = new CookieAuthenticationProvider + { + OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( + validateInterval: TimeSpan.FromMinutes(30), + regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) + }, + CookieName = ".AspNet.ApplicationCookie", + TicketDataFormat = new AspNetTicketDataFormat(new DataProtectorShim(dataProtector)) + }); + }); +``` + +### Use in controllers + +Access OWIN-registered services in controllers: + +```csharp +using Microsoft.AspNet.Identity.Owin; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SystemWebAdapters; +using Microsoft.Owin.Security; + +[Authorize] +public class AccountController : Controller +{ + public ApplicationSignInManager SignInManager => + HttpContext.GetOwinContext().Get(); + + public ApplicationUserManager UserManager => + HttpContext.GetOwinContext().GetUserManager(); + + private IAuthenticationManager AuthenticationManager => + HttpContext.GetOwinContext().Authentication; + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Login(LoginViewModel model) + { + var result = await SignInManager.PasswordSignInAsync( + model.Email, + model.Password, + model.RememberMe, + shouldLockout: false); + + if (result == SignInStatus.Success) + { + return RedirectToAction("Index", "Home"); + } + + ModelState.AddModelError("", "Invalid login attempt."); + return View(model); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public IActionResult Logout() + { + AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie); + return RedirectToAction("Index", "Home"); + } +} +``` + +### Key configuration points + +When migrating ASP.NET Framework Identity: + +* **Data protection**: Configure the same `ApplicationName` and key storage location in both ASP.NET Framework and ASP.NET Core +* **Per-request services**: Use `app.CreatePerOwinContext()` to register services created once per request +* **Data protection bridge**: Use `AspNetTicketDataFormat` with `DataProtectorShim` to bridge ASP.NET Core's `IDataProtector` to OWIN +* **Service access**: Access OWIN-registered services through `HttpContext.GetOwinContext()` +* **Cookie names**: Ensure the `CookieName` matches between applications when sharing authentication state + +## OWIN pipeline in HttpApplication events + +This pattern runs OWIN middleware within the emulated `HttpApplication` event pipeline, similar to how OWIN works in ASP.NET Framework's integrated pipeline mode. + +### When to use this pattern + +Use this approach when: + +* Your application relies on the ASP.NET Framework integrated pipeline +* OWIN middleware needs to execute at specific `HttpApplication` event stages +* You're migrating applications that use both `HttpApplication` events and OWIN together + +### Setup + +Configure the OWIN pipeline to run within `HttpApplication` events: + +```csharp +var builder = WebApplication.CreateBuilder(args); + +builder.Services + .AddSystemWebAdapters() + .AddOwinApp(app => + { + app.UseMyOwinMiddleware(); + app.UseStageMarker(PipelineStage.Authenticate); + }); + +var app = builder.Build(); + +app.UseSystemWebAdapters(); +app.Run(); +``` + +### Access services + +Access the `IServiceProvider` when configuring the OWIN pipeline: + +```csharp +builder.Services + .AddSystemWebAdapters() + .AddOwinApp((app, services) => + { + var configuration = services.GetRequiredService(); + app.UseMyOwinMiddleware(configuration); + app.UseStageMarker(PipelineStage.Authenticate); + }); +``` + +### HttpApplication event mapping + +The OWIN pipeline integrates with these `HttpApplication` events: + +* `AuthenticateRequest` / `PostAuthenticateRequest` +* `AuthorizeRequest` / `PostAuthorizeRequest` +* `ResolveRequestCache` / `PostResolveRequestCache` +* `MapRequestHandler` / `PostMapRequestHandler` +* `AcquireRequestState` / `PostAcquireRequestState` +* `PreRequestHandlerExecute` + +Use `.UseStageMarker(PipelineStage)` to control when OWIN middleware executes relative to these events. + +## Migration strategy + +When incorporating OWIN middleware into your ASP.NET Core application: + +1. **Identify OWIN dependencies**: Determine which OWIN middleware your application uses +1. **Choose integration pattern**: Select the appropriate pattern based on your application's needs +1. **Configure data protection**: Set up shared data protection for authentication cookie sharing +1. **Test authentication flow**: Verify authentication works correctly in the ASP.NET Core application +1. **Gradual conversion**: Plan to migrate OWIN middleware to native ASP.NET Core middleware over time +1. **Monitor compatibility**: Ensure OWIN middleware behavior matches expectations during migration + +## Additional resources + +* +* +* diff --git a/aspnetcore/migration/fx-to-core/index.md b/aspnetcore/migration/fx-to-core/index.md index b3b33b658fad..2798d07abe45 100644 --- a/aspnetcore/migration/fx-to-core/index.md +++ b/aspnetcore/migration/fx-to-core/index.md @@ -3,7 +3,7 @@ title: Migrate from ASP.NET Framework to ASP.NET Core author: wadepickett description: Your complete guide to migrating ASP.NET Framework applications to ASP.NET Core, with practical approaches and step-by-step guidance. ms.author: wpickett -ms.date: 07/17/2025 +ms.date: 11/10/2025 uid: migration/fx-to-core/index --- # Migrate from ASP.NET Framework to ASP.NET Core @@ -38,6 +38,8 @@ Many applications have cross-cutting concerns that span multiple layers and need * **Configuration management** - Managing settings that need to be shared or synchronized between applications * **Dependency injection** - Migrating from various DI containers to ASP.NET Core's built-in container +The generic host pattern can help address several of these concerns by bringing modern .NET infrastructure to ASP.NET Framework applications. For details, see . + ### Library Dependency Chains Supporting libraries often have complex dependency relationships that require careful upgrade ordering: diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md index b6b3bf4dcc47..22e170d397e6 100644 --- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md +++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md @@ -107,7 +107,7 @@ The following example uses the `HideColumnOptionsAsync` method to close the colu } ``` -### Response streaming is opt-in and how to opt-out +### HttpClient response streaming enabled by default In prior Blazor releases, response streaming for requests was opt-in. Now, response streaming is enabled by default. diff --git a/aspnetcore/release-notes/aspnetcore-2.1.md b/aspnetcore/release-notes/aspnetcore-2.1.md index d40f8793c401..7e73323786a6 100644 --- a/aspnetcore/release-notes/aspnetcore-2.1.md +++ b/aspnetcore/release-notes/aspnetcore-2.1.md @@ -166,7 +166,7 @@ For more information, see . ## Migrate from 2.0 to 2.1 -See [Migrate from ASP.NET Core 2.0 to 2.1](xref:migration/20_21). +See [Migrate from ASP.NET Core 2.0 to 2.1](xref:migration/20-to-21). ## Breaking changes diff --git a/aspnetcore/release-notes/aspnetcore-9/includes/asp0026.md b/aspnetcore/release-notes/aspnetcore-9/includes/asp0026.md index 6985c4b985ad..ceef60e60e3a 100644 --- a/aspnetcore/release-notes/aspnetcore-9/includes/asp0026.md +++ b/aspnetcore/release-notes/aspnetcore-9/includes/asp0026.md @@ -2,6 +2,9 @@ It seems intuitive that an `[Authorize]` attribute placed "closer" to an MVC action than an `[AllowAnonymous]` attribute would override the `[AllowAnonymous]` attribute and force authorization. However, this is not necessarily the case. What does matter is the relative order of the attributes. +> [!NOTE] +> The `[AllowAnonymous]` attribute doesn't disable authentication entirely. When credentials are sent to an endpoint with `[AllowAnonymous]`, the endpoint still authenticates those credentials and establishes the user's identity. The `[AllowAnonymous]` attribute only means that authentication is **not required**—the endpoint will run as anonymous only when no credentials are provided. This behavior can be useful for endpoints that need to work for both authenticated and anonymous users. + The following code shows examples where a closer `[Authorize]` attribute gets overridden by an `[AllowAnonymous]` attribute that is farther away. ```csharp @@ -53,8 +56,10 @@ public class MyController { // This produces no warning because the second, "closer" [AllowAnonymous] // clarifies that [Authorize] is intentionally overridden. - // Specifying AuthenticationSchemes can still be useful - // for endpoints that allow but don't require authenticated users. + // Specifying AuthenticationSchemes can be useful for endpoints that + // allow but don't require authenticated users. When credentials are sent, + // they will be authenticated; when no credentials are sent, the endpoint + // allows anonymous access. [Authorize(AuthenticationSchemes = "Cookies")] [AllowAnonymous] public IActionResult Privacy() => null; diff --git a/aspnetcore/security/authentication/scaffold-identity.md b/aspnetcore/security/authentication/scaffold-identity.md index 9d5b587716b2..18ce1ab12424 100644 --- a/aspnetcore/security/authentication/scaffold-identity.md +++ b/aspnetcore/security/authentication/scaffold-identity.md @@ -952,6 +952,6 @@ To prevent publishing static Identity assets to the web root, see