diff --git a/aspnetcore/fundamentals/aot/includes/aot_lib.md b/aspnetcore/fundamentals/aot/includes/aot_lib.md index 644609b04e54..e5dfed01f133 100644 --- a/aspnetcore/fundamentals/aot/includes/aot_lib.md +++ b/aspnetcore/fundamentals/aot/includes/aot_lib.md @@ -1,14 +1,14 @@ -### Libraries and Native AOT +### Use libraries with Native AOT -Many of the popular libraries used in ASP.NET Core projects currently have some compatibility issues when used in a project targeting Native AOT, such as: +Many popular libraries used in ASP.NET Core projects currently have some compatibility issues when they're incorporated into projects that target Native AOT, such as: -* Use of reflection to inspect and discover types. -* Conditionally loading libraries at runtime. -* Generating code on the fly to implement functionality. +* Using reflection to inspect and discover types +* Loading libraries conditionally at runtime +* Generating code on the fly to implement functionality -Libraries using these dynamic features need to be updated in order to work with Native AOT. They can be updated using tools like Roslyn source generators. +Libraries that use these dynamic features require updates to work with Native AOT. Various tools are available for applying the necessary updates, such as [Roslyn source generators](/dotnet/csharp/roslyn-sdk/#source-generators). -Library authors hoping to support Native AOT are encouraged to: +Library authors hoping to support Native AOT are encouraged to review the following articles: -* Read about [Native AOT compatibility requirements](/dotnet/core/deploying/native-aot/?tabs=net8plus). -* [Prepare the library for trimming](/dotnet/core/deploying/trimming/prepare-libraries-for-trimming). +* [Native AOT deployment](/dotnet/core/deploying/native-aot) +* [Prepare .NET libraries for trimming](/dotnet/core/deploying/trimming/prepare-libraries-for-trimming) diff --git a/aspnetcore/fundamentals/http-context.md b/aspnetcore/fundamentals/http-context.md index 2cd13e140258..5be92168b2a5 100644 --- a/aspnetcore/fundamentals/http-context.md +++ b/aspnetcore/fundamentals/http-context.md @@ -5,22 +5,22 @@ description: Learn about using HttpContext in ASP.NET Core apps. HttpContext isn monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra ms.custom: mvc -ms.date: 02/12/2025 +ms.date: 04/23/2026 uid: fundamentals/httpcontext + +# customer intent: As an ASP.NET developer, I want to understand how to access HttpContext in my ASP.NET Core apps, so I can address related exceptions and thread issues. --- -# Access `HttpContext` in ASP.NET Core +# Access HttpContext in ASP.NET Core [!INCLUDE[](~/includes/not-latest-version.md)] -:::moniker range=">= aspnetcore-6.0" - - encapsulates all information about an individual HTTP request and response. An `HttpContext` instance is initialized when an HTTP request is received. The `HttpContext` instance is accessible by middleware and app frameworks such as Web API controllers, Razor Pages, SignalR, gRPC, and more. +The encapsulates all information about an individual HTTP request and response. An `HttpContext` instance is initialized when an HTTP request is received. The `HttpContext` instance is accessible by middleware and app frameworks such as Web API controllers, Razor Pages, [SignalR](xref:signalr/introduction), gRPC, and more. -For information about using `HttpContext` with a HTTP request and response, see . +For information about using `HttpContext` with an HTTP request and response, see . -## Access `HttpContext` from Razor Pages +## Access HttpContext from Razor Pages -The Razor Pages exposes the property: +The Razor Pages exposes the property: ```csharp public class IndexModel : PageModel @@ -34,7 +34,7 @@ public class IndexModel : PageModel } ``` -The same property can be used in the corresponding Razor Page View: +You can use the same property in the corresponding Razor Page View: ```cshtml @page @@ -47,9 +47,9 @@ The same property can be used in the corresponding Razor Page View: } ``` -## Access `HttpContext` from a Razor view in MVC +## Access HttpContext from a Razor view in MVC -Razor views in the MVC pattern expose the `HttpContext` via the property on the view. The following example retrieves the current username in an intranet app using Windows Authentication: +Razor views in the MVC pattern expose the `HttpContext` via the property on the view. The following example retrieves the current username in an intranet app by using Windows Authentication: ```cshtml @{ @@ -59,9 +59,9 @@ Razor views in the MVC pattern expose the `HttpContext` via the property: +Controllers expose the property: ```csharp public class HomeController : Controller @@ -77,17 +77,21 @@ public class HomeController : Controller } ``` -## Access `HttpContext` from Minimal APIs +:::moniker range=">= aspnetcore-6.0" + +## Access HttpContext from Minimal APIs -To use `HttpContext` from Minimal APIs, add a `HttpContext` parameter: +To use `HttpContext` from [Minimal APIs](minimal-apis.md): ```csharp app.MapGet("/", (HttpContext context) => context.Response.WriteAsync("Hello World")); ``` -## Access `HttpContext` from middleware +:::moniker-end -To use `HttpContext` from custom middleware components, use the `HttpContext` parameter passed into the `Invoke` or `InvokeAsync` method: +## Access HttpContext from middleware + +To use `HttpContext` from custom middleware components, pass the `HttpContext` parameter into the `Invoke` or `InvokeAsync` method: ```csharp public class MyCustomMiddleware @@ -101,9 +105,11 @@ public class MyCustomMiddleware } ``` -## Access `HttpContext` from SignalR +:::moniker range=">= aspnetcore-6.0" + +## Access HttpContext from SignalR -To use `HttpContext` from SignalR, call the method on : +To use `HttpContext` from SignalR, call the on the : ```csharp public class MyHub : Hub @@ -117,13 +123,17 @@ public class MyHub : Hub } ``` -## Access `HttpContext` from gRPC methods +## Access HttpContext from gRPC methods -To use `HttpContext` from gRPC methods, see [Resolve `HttpContext` in gRPC methods](xref:grpc/aspnetcore#resolve-httpcontext-in-grpc-methods). +To use `HttpContext` from [gRPC](xref:grpc/aspnetcore) methods, see [Resolve HttpContext in gRPC methods](xref:grpc/aspnetcore#resolve-httpcontext-in-grpc-methods). + +:::moniker-end -## Access `HttpContext` from custom components +## Access HttpContext from custom components -For other framework and custom components that require access to `HttpContext`, the recommended approach is to register a dependency using the built-in [Dependency Injection (DI)](xref:fundamentals/dependency-injection) container. The DI container supplies the `IHttpContextAccessor` to any classes that declare it as a dependency in their constructors: +For other framework and custom components that require access to `HttpContext`, the recommended approach is to register a dependency by using the built-in [Dependency Injection (DI)](xref:fundamentals/dependency-injection) container. The DI container supplies the `IHttpContextAccessor` to any classes that declare it as a dependency in their constructors: + +:::moniker range=">= aspnetcore-6.0" ```csharp var builder = WebApplication.CreateBuilder(args); @@ -133,11 +143,27 @@ builder.Services.AddHttpContextAccessor(); builder.Services.AddTransient(); ``` +:::moniker-end +:::moniker range="< aspnetcore-6.0" + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddControllersWithViews(); + services.AddHttpContextAccessor(); + services.AddTransient(); +} +``` + +:::moniker-end + In the following example: -* `UserRepository` declares its dependency on `IHttpContextAccessor`. +* The `UserRepository` instance declares its dependency on `IHttpContextAccessor`. * The dependency is supplied when DI resolves the dependency chain and creates an instance of `UserRepository`. +:::moniker range=">= aspnetcore-6.0" + ```csharp public class UserRepository : IUserRepository { @@ -155,175 +181,71 @@ public class UserRepository : IUserRepository } ``` -## `HttpContext` access from a background thread - -`HttpContext` isn't thread-safe. Reading or writing properties of the `HttpContext` outside of processing a request can result in a . - -> [!NOTE] -> If your app generates sporadic `NullReferenceException` errors, review parts of the code that start background processing or that continue processing after a request completes. Look for mistakes, such as defining a controller method as `async void`. - -To safely do background work with `HttpContext` data: - -* Copy the required data during request processing. -* Pass the copied data to a background task. -* Do ***not*** reference `HttpContext` data in parallel tasks. Extract the data needed from the context before starting the parallel tasks. - -To avoid unsafe code, never pass `HttpContext` into a method that does background work. Pass the required data instead. In the following example, `SendEmail` calls `SendEmailCoreAsync` to start sending an email. The value of the `X-Correlation-Id` header is passed to `SendEmailCoreAsync` instead of the `HttpContext`. Code execution doesn't wait for `SendEmailCoreAsync` to complete: +:::moniker-end +:::moniker range="< aspnetcore-6.0" ```csharp -public class EmailController : Controller +public class UserRepository : IUserRepository { - public IActionResult SendEmail(string email) - { - var correlationId = HttpContext.Request.Headers["X-Correlation-Id"].ToString(); - - _ = SendEmailCoreAsync(correlationId); + private readonly IHttpContextAccessor _httpContextAccessor; - return View(); + public UserRepository(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; } - private async Task SendEmailCoreAsync(string correlationId) + public void LogCurrentUser() { - // ... + var username = _httpContextAccessor.HttpContext.User.Identity.Name; + service.LogAccessRequest(username); } } ``` -## `IHttpContextAccessor`/`HttpContext` in Razor components (Blazor) - -For more information, see . - :::moniker-end -:::moniker range="< aspnetcore-6.0" - - encapsulates all information about an individual HTTP request and response. An `HttpContext` instance is initialized when an HTTP request is received. The `HttpContext` instance is accessible by middleware and app frameworks such as Web API controllers, Razor Pages, SignalR, gRPC, and more. - -For information about using `HttpContext` with a HTTP request and response, see . - -## Access `HttpContext` from Razor Pages - -The Razor Pages exposes the property: - -```csharp -public class IndexModel : PageModel -{ - public void OnGet() - { - var message = HttpContext.Request.PathBase; - - // ... - } -} -``` - -The same property can be used in the corresponding Razor Page View: +## Access HttpContext from a background thread -```cshtml -@page -@model IndexModel +`HttpContext` isn't thread-safe. Reading or writing properties of the `HttpContext` outside of processing a request can result in a error. -@{ - var message = HttpContext.Request.PathBase; - - // ... -} -``` +> [!NOTE] +> If your app generates sporadic `NullReferenceException` errors, review parts of the code that start background processing or code that continues processing after a request completes. Look for mistakes, such as defining a controller method as `async void`. -## Access `HttpContext` from a Razor view in MVC +To safely do background work with `HttpContext` data: -Razor views in the MVC pattern expose the `HttpContext` via the property on the view. The following example retrieves the current username in an intranet app using Windows Authentication: +* Copy the required data during request processing. +* Pass the copied data to a background task. +* **Don't** reference `HttpContext` data in parallel tasks. Extract the data needed from the context before starting the parallel tasks. -```cshtml -@{ - var username = Context.User.Identity.Name; - - // ... -} -``` +To avoid unsafe code, never pass `HttpContext` into a method that does background work. Pass the required data instead. -## Access `HttpContext` from a controller +:::moniker range=">= aspnetcore-6.0" -Controllers expose the property: +In the following example, the `SendEmail` method calls the `SendEmailCoreAsync` method to start sending an email. The value of the `X-Correlation-Id` header is passed to `SendEmailCoreAsync` instead of the `HttpContext`. Code execution doesn't wait for `SendEmailCoreAsync` to complete: ```csharp -public class HomeController : Controller +public class EmailController : Controller { - public IActionResult About() + public IActionResult SendEmail(string email) { - var pathBase = HttpContext.Request.PathBase; + var correlationId = HttpContext.Request.Headers["X-Correlation-Id"].ToString(); - // ... + _ = SendEmailCoreAsync(correlationId); return View(); } -} -``` - -## Access `HttpContext` from middleware -When working with custom middleware components, `HttpContext` is passed into the `Invoke` or `InvokeAsync` method: - -```csharp -public class MyCustomMiddleware -{ - public Task InvokeAsync(HttpContext context) + private async Task SendEmailCoreAsync(string correlationId) { // ... } } ``` -## Access `HttpContext` from custom components - -For other framework and custom components that require access to `HttpContext`, the recommended approach is to register a dependency using the built-in [Dependency Injection (DI)](xref:fundamentals/dependency-injection) container. The DI container supplies the `IHttpContextAccessor` to any classes that declare it as a dependency in their constructors: - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddControllersWithViews(); - services.AddHttpContextAccessor(); - services.AddTransient(); -} -``` - -In the following example: - -* `UserRepository` declares its dependency on `IHttpContextAccessor`. -* The dependency is supplied when DI resolves the dependency chain and creates an instance of `UserRepository`. - -```csharp -public class UserRepository : IUserRepository -{ - private readonly IHttpContextAccessor _httpContextAccessor; - - public UserRepository(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - - public void LogCurrentUser() - { - var username = _httpContextAccessor.HttpContext.User.Identity.Name; - service.LogAccessRequest(username); - } -} -``` - -## `HttpContext` access from a background thread - -`HttpContext` isn't thread-safe. Reading or writing properties of the `HttpContext` outside of processing a request can result in a . - -> [!NOTE] -> If your app generates sporadic `NullReferenceException` errors, review parts of the code that start background processing or that continue processing after a request completes. Look for mistakes, such as defining a controller method as `async void`. - -To safely do background work with `HttpContext` data: - -* Copy the required data during request processing. -* Pass the copied data to a background task. -* Do ***not*** reference `HttpContext` data in parallel tasks. Extract the data needed from the context before starting the parallel tasks. +:::moniker-end +:::moniker range="< aspnetcore-6.0" -To avoid unsafe code, never pass the `HttpContext` into a method that does background work. Pass the required data instead. In the following example, `SendEmailCore` is called to start sending an email. The `correlationId` is passed to `SendEmailCore`, not the `HttpContext`. Code execution doesn't wait for `SendEmailCore` to complete: +In the following example, the `SendEmailCore` method is called to start sending an email. The `correlationId` parameter is passed to `SendEmailCore`, not the `HttpContext`. Code execution doesn't wait for `SendEmailCore` to complete: ```csharp public class EmailController : Controller @@ -344,8 +266,14 @@ public class EmailController : Controller } ``` -## `IHttpContextAccessor`/`HttpContext` in Razor components (Blazor) +:::moniker-end -For more information, see . +## Access IHttpContextAccessor or HttpContext in Razor components (Blazor) -:::moniker-end +If you want to access the `IHttpContextAccessor` or `HttpContext` in Razor components (Blazor apps), see . + +## Related content + +- [Use HttpContext in ASP.NET Core](xref:fundamentals/use-httpcontext) +- [Razor Pages architecture and concepts in ASP.NET Core](xref:razor-pages/index) +- [gRPC services with ASP.NET Core](xref:grpc/aspnetcore) \ No newline at end of file diff --git a/aspnetcore/fundamentals/http-requests.md b/aspnetcore/fundamentals/http-requests.md index 985d8fc1b2a9..fead522fa323 100644 --- a/aspnetcore/fundamentals/http-requests.md +++ b/aspnetcore/fundamentals/http-requests.md @@ -1,14 +1,16 @@ --- -title: Make HTTP requests using IHttpClientFactory in ASP.NET Core +title: HTTP Requests with IHttpClientFactory - ASP.NET Core author: stevejgordon description: Learn about using the IHttpClientFactory interface to manage logical HttpClient instances in ASP.NET Core. monikerRange: '>= aspnetcore-2.1' ms.author: tdykstra ms.custom: mvc -ms.date: 11/09/2021 +ms.date: 04/23/2026 uid: fundamentals/http-requests + +# customer intent: As an ASP.NET developer, I want to use the IHttpClientFactory interface in ASP.NET Core, so I can manage logical HttpClient instances. --- -# Make HTTP requests using IHttpClientFactory in ASP.NET Core +# Make HTTP requests with IHttpClientFactory in ASP.NET Core [!INCLUDE[](~/includes/not-latest-version.md)] @@ -16,16 +18,19 @@ uid: fundamentals/http-requests By [Kirk Larkin](https://github.com/serpent5), [Steve Gordon](https://github.com/stevejgordon), [Glenn Condron](https://github.com/glennc), and [Ryan Nowak](https://github.com/rynowak). -An can be registered and used to configure and create instances in an app. `IHttpClientFactory` offers the following benefits: +You can register the and use it to configure and create instances in an app. The `IHttpClientFactory` interface offers the following benefits: + +* Provides a central location for naming and configuring logical `HttpClient` instances. For example, a client named *github* can be registered and configured to access [GitHub](https://github.com/). A default client can be registered for general access. + +* Codifies the concept of outgoing middleware via delegating handlers in the `HttpClient` instance. Provides extensions for Polly-based middleware to take advantage of delegating handlers in `HttpClient`. -* Provides a central location for naming and configuring logical `HttpClient` instances. For example, a client named *github* could be registered and configured to access [GitHub](https://github.com/). A default client can be registered for general access. -* Codifies the concept of outgoing middleware via delegating handlers in `HttpClient`. Provides extensions for Polly-based middleware to take advantage of delegating handlers in `HttpClient`. * Manages the pooling and lifetime of underlying `HttpClientMessageHandler` instances. Automatic management avoids common DNS (Domain Name System) problems that occur when manually managing `HttpClient` lifetimes. -* Adds a configurable logging experience (via `ILogger`) for all requests sent through clients created by the factory. -The sample code in this topic version uses to deserialize JSON content returned in HTTP responses. For samples that use `Json.NET` and `ReadAsAsync`, use the version selector to select a 2.x version of this topic. +* Adds a configurable logging experience (via the `ILogger`) for all requests sent through clients created by the factory. -## Consumption patterns +This article describes how to make HTTP requests by using `IHttpClientFactory` in ASP.NET Core applications. The sample code version uses to deserialize JSON content returned in HTTP responses. For samples that use `Json.NET` and `ReadAsAsync`, use the browser **Version** selector to select a 2.x version of this article. + +## Review consumption patterns There are several ways `IHttpClientFactory` can be used in an app: @@ -38,93 +43,93 @@ The best approach depends upon the app's requirements. ### Basic usage -Register `IHttpClientFactory` by calling `AddHttpClient` in `Program.cs`: +Register `IHttpClientFactory` by calling the `AddHttpClient` method in the _Program.cs_ file: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddHttpClientBasic" highlight="4"::: -An `IHttpClientFactory` can be requested using [dependency injection (DI)](xref:fundamentals/dependency-injection). The following code uses `IHttpClientFactory` to create an `HttpClient` instance: +An `IHttpClientFactory` can be requested by using [dependency injection (DI)](xref:fundamentals/dependency-injection). The following code uses `IHttpClientFactory` to create an `HttpClient` instance: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Pages/Consumption/Basic.cshtml.cs" id="snippet_Class" highlight="5-6,23"::: -Using `IHttpClientFactory` like in the preceding example is a good way to refactor an existing app. It has no impact on how `HttpClient` is used. In places where `HttpClient` instances are created in an existing app, replace those occurrences with calls to . +In the example, the call to `IHttpClientFactory` is a good way to refactor an existing app. This approach has no effect on how `HttpClient` is used. + +In scenarios where `HttpClient` instances are created in an existing app, replace the occurrences with calls to the . ### Named clients -Named clients are a good choice when: +Named clients are suitable for the following scenarios: * The app requires many distinct uses of `HttpClient`. -* Many `HttpClient`s have different configuration. +* There are many `HttpClient` instances with different configurations. -Specify configuration for a named `HttpClient` during its registration in `Program.cs`: +Specify the configuration for a named `HttpClient` instance during its registration in the _Program.cs_ file: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddHttpClientNamed"::: -In the preceding code the client is configured with: +In the code snippet, the client is configured with: * The base address `https://api.github.com/`. * Two headers required to work with the GitHub API. -#### CreateClient +#### CreateClient method -Each time is called: +For each call to the : * A new instance of `HttpClient` is created. * The configuration action is called. -To create a named client, pass its name into `CreateClient`: +To create a named client, pass the client name into the `CreateClient` method: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Pages/Consumption/NamedClient.cshtml.cs" id="snippet_Class" highlight="12"::: -In the preceding code, the request doesn't need to specify a hostname. The code can pass just the path, since the base address configured for the client is used. +In the code snippet, the request doesn't need to specify a hostname. The code can pass the path only because the base address configured for the client is used. ### Typed clients -Typed clients: +Typed clients provide several benefits: -* Provide the same capabilities as named clients without the need to use strings as keys. -* Provides IntelliSense and compiler help when consuming clients. -* Provide a single location to configure and interact with a particular `HttpClient`. For example, a single typed client might be used: - * For a single backend endpoint. - * To encapsulate all logic dealing with the endpoint. -* Work with DI and can be injected where required in the app. +* Access to the same capabilities as named clients without the need to use strings as keys. +* IntelliSense and compiler help when consuming clients. +* The ability to define a single location to configure and interact with a particular `HttpClient` instance. For example, a single typed client might be used for a single backend endpoint, or to encapsulate all logic dealing with the endpoint. +* Support for DI and injection where the app requires the functionality. A typed client accepts an `HttpClient` parameter in its constructor: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/GitHub/GitHubService.cs" id="snippet_Class" highlight="5"::: -In the preceding code: +In the code snippet: * The configuration is moved into the typed client. * The provided `HttpClient` instance is stored as a private field. API-specific methods can be created that expose `HttpClient` functionality. For example, the `GetAspNetCoreDocsBranches` method encapsulates code to retrieve docs GitHub branches. -The following code calls in `Program.cs` to register the `GitHubService` typed client class: +The following code calls in the _Program.cs_ file to register the `GitHubService` typed client class: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddHttpClientTyped"::: -The typed client is registered as transient with DI. In the preceding code, `AddHttpClient` registers `GitHubService` as a transient service. This registration uses a factory method to: +The typed client is registered as transient with DI. In the snippet, the `AddHttpClient` method registers `GitHubService` as a transient service. This registration uses a factory method to: -1. Create an instance of `HttpClient`. -1. Create an instance of `GitHubService`, passing in the instance of `HttpClient` to its constructor. +- Create an instance of `HttpClient`. +- Create an instance of `GitHubService` and passing in the instance of `HttpClient` to its constructor. The typed client can be injected and consumed directly: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Pages/Consumption/TypedClient.cshtml.cs" id="snippet_Class" highlight="5-6,14"::: -The configuration for a typed client can also be specified during its registration in `Program.cs`, rather than in the typed client's constructor: +The configuration for a typed client can also be specified during its registration in the _Program.cs_ file, rather than in the typed client's constructor: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Snippets/Program.cs" id="snippet_AddHttpClientTypedInline"::: ### Generated clients -`IHttpClientFactory` can be used in combination with third-party libraries such as [Refit](https://github.com/reactiveui/refit). Refit is a REST library for .NET. It converts REST APIs into live interfaces. Call `AddRefitClient` to generate a dynamic implementation of an interface, which uses `HttpClient` to make the external HTTP calls. +The `IHttpClientFactory` interface can be used in combination with third-party libraries such as [Refit](https://github.com/reactiveui/refit). Refit is a REST library for .NET that converts REST APIs into live interfaces. Call the `AddRefitClient` method to generate a dynamic implementation of an interface. The method uses `HttpClient` to make the external HTTP calls. A custom interface represents the external API: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/GitHub/IGitHubClient.cs" id="snippet_Interface"::: -Call `AddRefitClient` to generate the dynamic implementation and then call `ConfigureHttpClient` to configure the underlying `HttpClient`: +Call `AddRefitClient` to generate the dynamic implementation, and then call the `ConfigureHttpClient` method to configure the underlying `HttpClient` instance: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddRefitClient" highlight="1-2"::: @@ -141,7 +146,7 @@ In the preceding examples, all HTTP requests use the GET HTTP verb. `HttpClient` * DELETE * PATCH -For a complete list of supported HTTP verbs, see . +For a complete list of supported HTTP verbs, see the . The following example shows how to make an HTTP POST request: @@ -149,10 +154,10 @@ The following example shows how to make an HTTP POST request: In the preceding code, the `CreateItemAsync` method: -* Serializes the `TodoItem` parameter to JSON using `System.Text.Json`. -* Creates an instance of to package the serialized JSON for sending in the HTTP request's body. -* Calls to send the JSON content to the specified URL. This is a relative URL that gets added to the [HttpClient.BaseAddress](xref:System.Net.Http.HttpClient.BaseAddress). -* Calls to throw an exception if the response status code doesn't indicate success. +* Serializes the `TodoItem` parameter to JSON by using `System.Text.Json`. +* Creates an instance of to package the serialized JSON for sending in the HTTP request body. +* Calls the to send the JSON content to the specified URL. The value is a relative URL that is added to the [HttpClient.BaseAddress](xref:System.Net.Http.HttpClient.BaseAddress). +* Calls the to throw an exception if the response status code doesn't indicate success. `HttpClient` also supports other types of content. For example, and . For a complete list of supported content, see . @@ -160,59 +165,54 @@ The following example shows an HTTP PUT request: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Snippets/TodoClient.cs" id="snippet_PUT"::: -The preceding code is similar to the POST example. The `SaveItemAsync` method calls instead of `PostAsync`. +The code snippet is similar to the POST example. The `SaveItemAsync` method calls the instead of `PostAsync`. The following example shows an HTTP DELETE request: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Snippets/TodoClient.cs" id="snippet_DELETE"::: -In the preceding code, the `DeleteItemAsync` method calls . Because HTTP DELETE requests typically contain no body, the `DeleteAsync` method doesn't provide an overload that accepts an instance of `HttpContent`. +In the code snippet, the `DeleteItemAsync` method calls . Because HTTP DELETE requests typically contain no body, the `DeleteAsync` method doesn't provide an overload that accepts an instance of `HttpContent`. To learn more about using different HTTP verbs with `HttpClient`, see . -## Outgoing request middleware +## Use outgoing request middleware -`HttpClient` has the concept of delegating handlers that can be linked together for outgoing HTTP requests. `IHttpClientFactory`: +`HttpClient` has the concept of delegating handlers that can be linked together for outgoing HTTP requests. The `IHttpClientFactory` interface provides the following benefits: -* Simplifies defining the handlers to apply for each named client. -* Supports registration and chaining of multiple handlers to build an outgoing request middleware pipeline. Each of these handlers is able to perform work before and after the outgoing request. This pattern: - * Is similar to the inbound middleware pipeline in ASP.NET Core. - * Provides a mechanism to manage cross-cutting concerns around HTTP requests, such as: - * caching - * error handling - * serialization - * logging +* Define the handlers to apply for each named client by using a simplified process. +* Register and chain multiple handlers to build an outgoing request middleware pipeline. Each handler can perform work before and after the outgoing request. This pattern is similar to the inbound middleware pipeline in ASP.NET Core. +* Manage cross-cutting concerns around HTTP requests, such as caching, error handling, serialization, and logging. To create a delegating handler: -* Derive from . -* Override . Execute code before passing the request to the next handler in the pipeline: +* Derive from the . +* Override the . Execute code before passing the request to the next handler in the pipeline: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Handlers/ValidateHeaderHandler.cs" id="snippet_Class"::: -The preceding code checks if the `X-API-KEY` header is in the request. If `X-API-KEY` is missing, is returned. +The code snippet checks if the `X-API-KEY` header is in the request. If `X-API-KEY` is missing, the code returns the status code. -More than one handler can be added to the configuration for an `HttpClient` with : +More than one handler can be added to the configuration for an `HttpClient` instance by using the : :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddHttpMessageHandler"::: -In the preceding code, the `ValidateHeaderHandler` is registered with DI. Once registered, can be called, passing in the type for the handler. +In the code snippet, the `ValidateHeaderHandler` is registered with DI. After registration, the can be called, passing in the type for the handler. -Multiple handlers can be registered in the order that they should execute. Each handler wraps the next handler until the final `HttpClientHandler` executes the request: +Multiple handlers can be registered in the order they should execute. Each handler wraps the next handler until the final `HttpClientHandler` executes the request: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddHttpMessageHandlerMultiple"::: -In the preceding code, `SampleHandler1` runs first, before `SampleHandler2`. +In the code snippet, `SampleHandler1` runs first, before `SampleHandler2`. ### Use DI in outgoing request middleware When `IHttpClientFactory` creates a new delegating handler, it uses DI to fulfill the handler's constructor parameters. `IHttpClientFactory` creates a **separate** DI scope for each handler, which can lead to surprising behavior when a handler consumes a *scoped* service. -For example, consider the following interface and its implementation, which represents a task as an operation with an identifier, `OperationId`: +Consider the following interface and its implementation, which represents a task as an operation with an identifier, `OperationId`: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Models/OperationScoped.cs" id="snippet_Types"::: -As its name suggests, `IOperationScoped` is registered with DI using a *scoped* lifetime: +As the name suggests, `IOperationScoped` is registered with DI by using a *scoped* lifetime: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_OperationScoped"::: @@ -220,25 +220,25 @@ The following delegating handler consumes and uses `IOperationScoped` to set the :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Handlers/OperationHandler.cs" id="snippet_Class" highlight="5-6,11"::: -In the [`HttpRequestsSample` download](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/http-requests/samples/6.x/HttpRequestsSample), navigate to `/Operation` and refresh the page. The request scope value changes for each request, but the handler scope value only changes every 5 seconds. +In the [HttpRequestsSample download](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/http-requests/samples/6.x/HttpRequestsSample), go to the _/Operation_ folder and refresh the page. The request scope value changes for each request, but the handler scope value only changes every 5 seconds. Handlers can depend upon services of any scope. Services that handlers depend upon are disposed when the handler is disposed. Use one of the following approaches to share per-request state with message handlers: -* Pass data into the handler using . -* Use to access the current request. -* Create a custom storage object to pass the data. +* Pass data into the handler by using the . +* Use the to access the current request. +* Create a custom storage object for passing the data. ## Use Polly-based handlers -`IHttpClientFactory` integrates with the third-party library [Polly](https://github.com/App-vNext/Polly). Polly is a comprehensive resilience and transient fault-handling library for .NET. It allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner. +The `IHttpClientFactory` interface integrates with the third-party library [Polly](https://github.com/App-vNext/Polly). Polly is a comprehensive resilience and transient fault-handling library for .NET. It allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner. Extension methods are provided to enable the use of Polly policies with configured `HttpClient` instances. The Polly extensions support adding Polly-based handlers to clients. Polly requires the [Microsoft.Extensions.Http.Polly](https://www.nuget.org/packages/Microsoft.Extensions.Http.Polly/) NuGet package. ### Handle transient faults -Faults typically occur when external HTTP calls are transient. allows a policy to be defined to handle transient errors. Policies configured with `AddTransientHttpErrorPolicy` handle the following responses: +Faults typically occur when external HTTP calls are transient. allows a policy to be defined to handle transient errors. Policies configured with the `AddTransientHttpErrorPolicy` method handle the following responses: * * HTTP 5xx @@ -248,27 +248,27 @@ Faults typically occur when external HTTP calls are transient. . The following `AddPolicyHandler` overload inspects the request to decide which policy to apply: +Extension methods are provided to add Polly-based handlers, for example, the . The following `AddPolicyHandler` overload inspects the request to decide which policy to apply: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddHttpClientPollyDynamic"::: -In the preceding code, if the outgoing request is an HTTP GET, a 10-second timeout is applied. For any other HTTP method, a 30-second timeout is used. +In the code snippet, if the outgoing request is an HTTP GET, a 10-second timeout is applied. For any other HTTP method, a 30-second timeout is used. ### Add multiple Polly handlers -It's common to nest Polly policies: +It's common practice to nest Polly policies: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddHttpClientPollyMultiple"::: -In the preceding example: +This example adds two handlers: -* Two handlers are added. -* The first handler uses to add a retry policy. Failed requests are retried up to three times. -* The second `AddTransientHttpErrorPolicy` call adds a circuit breaker policy. Further external requests are blocked for 30 seconds if 5 failed attempts occur sequentially. Circuit breaker policies are stateful. All calls through this client share the same circuit state. +* The first handler uses the to add a retry policy. Failed requests are retried up to three times. + +* The second `AddTransientHttpErrorPolicy` call adds a circuit breaker policy. Further external requests are blocked for 30 seconds if five failed attempts occur sequentially. Circuit breaker policies are stateful. All calls through this client share the same circuit state. ### Add policies from the Polly registry @@ -276,70 +276,69 @@ An approach to managing regularly used policies is to define them once and regis :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Snippets/Program.cs" id="snippet_AddHttpClientPollyRegistry"::: -In the preceding code: - -* Two policies, `Regular` and `Long`, are added to the Polly registry. -* configures individual named clients to use these policies from the Polly registry. +The code snippet adds two policies to the Polly registry, `Regular` and `Long`. The code calls the to configure individual named clients to use these policies from the Polly registry. For more information on `IHttpClientFactory` and Polly integrations, see the [Polly wiki](https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory). ## HttpClient and lifetime management -A new `HttpClient` instance is returned each time `CreateClient` is called on the `IHttpClientFactory`. An is created per named client. The factory manages the lifetimes of the `HttpMessageHandler` instances. +A new `HttpClient` instance is returned each time `CreateClient` is called on the `IHttpClientFactory`. An is created for each named client. The factory manages the lifetimes of the `HttpMessageHandler` instances. -`IHttpClientFactory` pools the `HttpMessageHandler` instances created by the factory to reduce resource consumption. An `HttpMessageHandler` instance may be reused from the pool when creating a new `HttpClient` instance if its lifetime hasn't expired. +`IHttpClientFactory` pools the `HttpMessageHandler` instances created by the factory to reduce resource consumption. An `HttpMessageHandler` instance might be reused from the pool when creating a new `HttpClient` instance, if its lifetime isn't expired. -Pooling of handlers is desirable as each handler typically manages its own underlying HTTP connections. Creating more handlers than necessary can result in connection delays. Some handlers also keep connections open indefinitely, which can prevent the handler from reacting to DNS (Domain Name System) changes. +Pooling of handlers is desirable as each handler typically manages its own underlying HTTP connections. Creating more handlers than necessary can result in connection delays. Some handlers also keep connections open indefinitely, which can prevent the handler from reacting to DNS changes. -The default handler lifetime is two minutes. The default value can be overridden on a per named client basis: +The default handler lifetime is 2 minutes. The default value can be overridden on a per-named client basis: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddHttpClientHandlerLifetime"::: -`HttpClient` instances can generally be treated as .NET objects **not** requiring disposal. Disposal cancels outgoing requests and guarantees the given `HttpClient` instance can't be used after calling . `IHttpClientFactory` tracks and disposes resources used by `HttpClient` instances. +`HttpClient` instances can generally be treated as .NET objects that **don't** require disposal. Disposal cancels outgoing requests and guarantees the given `HttpClient` instance can't be used after calling . `IHttpClientFactory` tracks and disposes resources used by `HttpClient` instances. Keeping a single `HttpClient` instance alive for a long duration is a common pattern used before the inception of `IHttpClientFactory`. This pattern becomes unnecessary after migrating to `IHttpClientFactory`. -### Alternatives to IHttpClientFactory +### Explore alternatives to IHttpClientFactory Using `IHttpClientFactory` in a DI-enabled app avoids: * Resource exhaustion problems by pooling `HttpMessageHandler` instances. * Stale DNS problems by cycling `HttpMessageHandler` instances at regular intervals. -There are alternative ways to solve the preceding problems using a long-lived instance. +There are alternative ways to solve the preceding problems by using a long-lived instance. * Create an instance of `SocketsHttpHandler` when the app starts and use it for the life of the app. * Configure to an appropriate value based on DNS refresh times. -* Create `HttpClient` instances using `new HttpClient(handler, disposeHandler: false)` as needed. +* Create `HttpClient` instances by using `new HttpClient(handler, disposeHandler: false)` as needed. -The preceding approaches solve the resource management problems that `IHttpClientFactory` solves in a similar way. +The alternate approaches solve the resource management problems that `IHttpClientFactory` solves in a similar way. * The `SocketsHttpHandler` shares connections across `HttpClient` instances. This sharing prevents socket exhaustion. * The `SocketsHttpHandler` cycles connections according to `PooledConnectionLifetime` to avoid stale DNS problems. -## Logging +## Log messages and response status -Clients created via `IHttpClientFactory` record log messages for all requests. Enable the appropriate information level in the logging configuration to see the default log messages. Additional logging, such as the logging of request headers, is only included at trace level. +Clients created via `IHttpClientFactory` record log messages for all requests. Enable the appropriate information level in the logging configuration so you can see the default log messages. Other logging, such as the logging of request headers, is only included at trace level. -The log category used for each client includes the name of the client. A client named *MyNamedClient*, for example, logs messages with a category of "System.Net.Http.HttpClient.**MyNamedClient**.LogicalHandler". Messages suffixed with *LogicalHandler* occur outside the request handler pipeline. On the request, messages are logged before any other handlers in the pipeline have processed it. On the response, messages are logged after any other pipeline handlers have received the response. +The log category used for each client includes the name of the client. A client named *MyNamedClient*, for example, logs messages with a category of "System.Net.Http.HttpClient.**MyNamedClient**.LogicalHandler." Messages that have the *LogicalHandler* suffix occur outside the request handler pipeline. On the request, messages are logged before any other handlers in the pipeline process them. On the response, messages are logged after any other pipeline handlers receive the response. -Logging also occurs inside the request handler pipeline. In the *MyNamedClient* example, those messages are logged with the log category "System.Net.Http.HttpClient.**MyNamedClient**.ClientHandler". For the request, this occurs after all other handlers have run and immediately before the request is sent. On the response, this logging includes the state of the response before it passes back through the handler pipeline. +Logging also occurs inside the request handler pipeline. In the *MyNamedClient* example, those messages are logged with the log category "System.Net.Http.HttpClient.**MyNamedClient**.ClientHandler." For the request, the logging occurs after all other handlers run and immediately before the request is sent. On the response, the logging includes the state of the response before it passes back through the handler pipeline. -Enabling logging outside and inside the pipeline enables inspection of the changes made by the other pipeline handlers. This may include changes to request headers or to the response status code. +Enabling logging outside and inside the pipeline enables inspection of the changes made by the other pipeline handlers. The logging might include changes to request headers or to the response status code. Including the name of the client in the log category enables log filtering for specific named clients. ## Configure the HttpMessageHandler -It may be necessary to control the configuration of the inner `HttpMessageHandler` used by a client. +It might be necessary to control the configuration of the inner `HttpMessageHandler` used by a client. An `IHttpClientBuilder` is returned when adding named or typed clients. The extension method can be used to define a delegate. The delegate is used to create and configure the primary `HttpMessageHandler` used by that client: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Program.cs" id="snippet_AddHttpClientConfigureHttpMessageHandler"::: -## Cookies +## Work with cookies -The pooled `HttpMessageHandler` instances results in `CookieContainer` objects being shared. Unanticipated `CookieContainer` object sharing often results in incorrect code. For apps that require cookies, consider either: +The pooled `HttpMessageHandler` instances results in `CookieContainer` objects being shared. Unanticipated `CookieContainer` object sharing often results in incorrect code. + +For apps that require cookies, consider: * Disabling automatic cookie handling * Avoiding `IHttpClientFactory` @@ -363,24 +362,17 @@ In the following example: :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsConsoleSample/Program.cs" highlight="10-11,17-18,40-41,56"::: -## Header propagation middleware +## Use header propagation middleware Header propagation is an ASP.NET Core middleware to propagate HTTP headers from the incoming request to the outgoing `HttpClient` requests. To use header propagation: * Install the [Microsoft.AspNetCore.HeaderPropagation](https://www.nuget.org/packages/Microsoft.AspNetCore.HeaderPropagation) package. -* Configure the `HttpClient` and middleware pipeline in `Program.cs`: - :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Snippets/Program.cs" id="snippet_AddHttpClientHeaderPropagation" highlight="4-10,17"::: +* Configure the `HttpClient` instance and middleware pipeline in the _Program.cs_ file: -* Make outbound requests using the configured `HttpClient` instance, which includes the added headers. - -## Additional resources + :::code language="csharp" source="http-requests/samples/6.x/HttpRequestsSample/Snippets/Program.cs" id="snippet_AddHttpClientHeaderPropagation" highlight="4-10,17"::: -* [View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/http-requests/samples) ([how to download](xref:fundamentals/index#how-to-download-a-sample)) -* [Use HttpClientFactory to implement resilient HTTP requests](/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests) -* [Implement HTTP call retries with exponential backoff with HttpClientFactory and Polly policies](/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly) -* [Implement the Circuit Breaker pattern](/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-circuit-breaker-pattern) -* [How to serialize and deserialize JSON in .NET](/dotnet/standard/serialization/system-text-json-how-to) +* Make outbound requests by using the configured `HttpClient` instance, which includes the added headers. :::moniker-end @@ -420,7 +412,7 @@ An `IHttpClientFactory` can be requested using [dependency injection (DI)](xref: :::code language="csharp" source="http-requests/samples/3.x/HttpClientFactorySample/Pages/BasicUsage.cshtml.cs" id="snippet1" highlight="9-12,21"::: -Using `IHttpClientFactory` like in the preceding example is a good way to refactor an existing app. It has no impact on how `HttpClient` is used. In places where `HttpClient` instances are created in an existing app, replace those occurrences with calls to . +Using `IHttpClientFactory` like in the preceding example is a good way to refactor an existing app. It has no effect on how `HttpClient` is used. In places where `HttpClient` instances are created in an existing app, replace those occurrences with calls to . ### Named clients @@ -494,7 +486,7 @@ The configuration for a typed client can be specified during registration in `St :::code language="csharp" source="http-requests/samples/3.x/HttpClientFactorySample/Startup.cs" id="snippet4"::: -The `HttpClient` can be encapsulated within a typed client. Rather than exposing it as a property, define a method which calls the `HttpClient` instance internally: +The `HttpClient` can be encapsulated within a typed client. Rather than exposing it as a property, define a method that calls the `HttpClient` instance internally: :::code language="csharp" source="http-requests/samples/3.x/HttpClientFactorySample/GitHub/RepoService.cs" id="snippet1" highlight="4"::: @@ -575,7 +567,7 @@ In the preceding code, the `CreateItemAsync` method: * Serializes the `TodoItem` parameter to JSON using `System.Text.Json`. This uses an instance of to configure the serialization process. * Creates an instance of to package the serialized JSON for sending in the HTTP request's body. * Calls to send the JSON content to the specified URL. This is a relative URL that gets added to the [HttpClient.BaseAddress](xref:System.Net.Http.HttpClient.BaseAddress). -* Calls to throw an exception if the response status code does not indicate success. +* Calls to throw an exception if the response status code doesn't indicate success. `HttpClient` also supports other types of content. For example, and . For a complete list of supported content, see . @@ -583,7 +575,7 @@ The following example shows an HTTP PUT request: :::code language="csharp" source="http-requests/samples/3.x/HttpRequestsSample/Models/TodoClient.cs" id="snippet_PUT"::: -The preceding code is very similar to the POST example. The `SaveItemAsync` method calls instead of `PostAsync`. +The preceding code is similar to the POST example. The `SaveItemAsync` method calls instead of `PostAsync`. The following example shows an HTTP DELETE request: @@ -689,7 +681,7 @@ In the preceding example: * Two handlers are added. * The first handler uses to add a retry policy. Failed requests are retried up to three times. -* The second `AddTransientHttpErrorPolicy` call adds a circuit breaker policy. Further external requests are blocked for 30 seconds if 5 failed attempts occur sequentially. Circuit breaker policies are stateful. All calls through this client share the same circuit state. +* The second `AddTransientHttpErrorPolicy` call adds a circuit breaker policy. Further external requests are blocked for 30 seconds if five failed attempts occur sequentially. Circuit breaker policies are stateful. All calls through this client share the same circuit state. ### Add policies from the Polly registry @@ -706,13 +698,13 @@ For more information on `IHttpClientFactory` and Polly integrations, see the [Po ## HttpClient and lifetime management -A new `HttpClient` instance is returned each time `CreateClient` is called on the `IHttpClientFactory`. An is created per named client. The factory manages the lifetimes of the `HttpMessageHandler` instances. +A new `HttpClient` instance is returned each time `CreateClient` is called on the `IHttpClientFactory`. An is created for each named client. The factory manages the lifetimes of the `HttpMessageHandler` instances. -`IHttpClientFactory` pools the `HttpMessageHandler` instances created by the factory to reduce resource consumption. An `HttpMessageHandler` instance may be reused from the pool when creating a new `HttpClient` instance if its lifetime hasn't expired. +`IHttpClientFactory` pools the `HttpMessageHandler` instances created by the factory to reduce resource consumption. An `HttpMessageHandler` instance might be reused from the pool when creating a new `HttpClient` instance, if its lifetime isn't expired. Pooling of handlers is desirable as each handler typically manages its own underlying HTTP connections. Creating more handlers than necessary can result in connection delays. Some handlers also keep connections open indefinitely, which can prevent the handler from reacting to DNS (Domain Name System) changes. -The default handler lifetime is two minutes. The default value can be overridden on a per named client basis: +The default handler lifetime is two minutes. The default value can be overridden on a per-named client basis: :::code language="csharp" source="http-requests/samples/3.x/HttpClientFactorySample/Startup5.cs" id="snippet1"::: @@ -751,19 +743,19 @@ Call extension method can be used to define a delegate. The delegate is used to create and configure the primary `HttpMessageHandler` used by that client: @@ -800,13 +792,6 @@ Header propagation is an ASP.NET Core middleware to propagate HTTP headers from var response = client.GetAsync(...); ``` -## Additional resources - -* [Use HttpClientFactory to implement resilient HTTP requests](/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests) -* [Implement HTTP call retries with exponential backoff with HttpClientFactory and Polly policies](/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly) -* [Implement the Circuit Breaker pattern](/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-circuit-breaker-pattern) -* [How to serialize and deserialize JSON in .NET](/dotnet/standard/serialization/system-text-json-how-to) - :::moniker-end :::moniker range=">= aspnetcore-3.0 < aspnetcore-5.0" @@ -845,7 +830,7 @@ An `IHttpClientFactory` can be requested using [dependency injection (DI)](xref: :::code language="csharp" source="http-requests/samples/3.x/HttpClientFactorySample/Pages/BasicUsage.cshtml.cs" id="snippet1" highlight="9-12,21"::: -Using `IHttpClientFactory` like in the preceding example is a good way to refactor an existing app. It has no impact on how `HttpClient` is used. In places where `HttpClient` instances are created in an existing app, replace those occurrences with calls to . +Using `IHttpClientFactory` like in the preceding example is a good way to refactor an existing app. It has no effect on how `HttpClient` is used. In places where `HttpClient` instances are created in an existing app, replace those occurrences with calls to . ### Named clients @@ -915,7 +900,7 @@ The configuration for a typed client can be specified during registration in `St :::code language="csharp" source="http-requests/samples/3.x/HttpClientFactorySample/Startup.cs" id="snippet4"::: -The `HttpClient` can be encapsulated within a typed client. Rather than exposing it as a property, define a method which calls the `HttpClient` instance internally: +The `HttpClient` can be encapsulated within a typed client. Rather than exposing it as a property, define a method that calls the `HttpClient` instance internally: :::code language="csharp" source="http-requests/samples/3.x/HttpClientFactorySample/GitHub/RepoService.cs" id="snippet1" highlight="4"::: @@ -996,7 +981,7 @@ In the preceding code, the `CreateItemAsync` method: * Serializes the `TodoItem` parameter to JSON using `System.Text.Json`. This uses an instance of to configure the serialization process. * Creates an instance of to package the serialized JSON for sending in the HTTP request's body. * Calls to send the JSON content to the specified URL. This is a relative URL that gets added to the [HttpClient.BaseAddress](xref:System.Net.Http.HttpClient.BaseAddress). -* Calls to throw an exception if the response status code does not indicate success. +* Calls to throw an exception if the response status code doesn't indicate success. `HttpClient` also supports other types of content. For example, and . For a complete list of supported content, see . @@ -1004,7 +989,7 @@ The following example shows an HTTP PUT request: :::code language="csharp" source="http-requests/samples/3.x/HttpRequestsSample/Models/TodoClient.cs" id="snippet_PUT"::: -The preceding code is very similar to the POST example. The `SaveItemAsync` method calls instead of `PostAsync`. +The preceding code is similar to the POST example. The `SaveItemAsync` method calls instead of `PostAsync`. The following example shows an HTTP DELETE request: @@ -1110,7 +1095,7 @@ In the preceding example: * Two handlers are added. * The first handler uses to add a retry policy. Failed requests are retried up to three times. -* The second `AddTransientHttpErrorPolicy` call adds a circuit breaker policy. Further external requests are blocked for 30 seconds if 5 failed attempts occur sequentially. Circuit breaker policies are stateful. All calls through this client share the same circuit state. +* The second `AddTransientHttpErrorPolicy` call adds a circuit breaker policy. Further external requests are blocked for 30 seconds if five failed attempts occur sequentially. Circuit breaker policies are stateful. All calls through this client share the same circuit state. ### Add policies from the Polly registry @@ -1127,13 +1112,13 @@ For more information on `IHttpClientFactory` and Polly integrations, see the [Po ## HttpClient and lifetime management -A new `HttpClient` instance is returned each time `CreateClient` is called on the `IHttpClientFactory`. An is created per named client. The factory manages the lifetimes of the `HttpMessageHandler` instances. +A new `HttpClient` instance is returned each time `CreateClient` is called on the `IHttpClientFactory`. An is created for each named client. The factory manages the lifetimes of the `HttpMessageHandler` instances. -`IHttpClientFactory` pools the `HttpMessageHandler` instances created by the factory to reduce resource consumption. An `HttpMessageHandler` instance may be reused from the pool when creating a new `HttpClient` instance if its lifetime hasn't expired. +`IHttpClientFactory` pools the `HttpMessageHandler` instances created by the factory to reduce resource consumption. An `HttpMessageHandler` instance might be reused from the pool when creating a new `HttpClient` instance, if its lifetime isn't expired. Pooling of handlers is desirable as each handler typically manages its own underlying HTTP connections. Creating more handlers than necessary can result in connection delays. Some handlers also keep connections open indefinitely, which can prevent the handler from reacting to DNS (Domain Name System) changes. -The default handler lifetime is two minutes. The default value can be overridden on a per named client basis: +The default handler lifetime is two minutes. The default value can be overridden on a per-named client basis: :::code language="csharp" source="http-requests/samples/3.x/HttpClientFactorySample/Startup5.cs" id="snippet1"::: @@ -1172,19 +1157,19 @@ Call extension method can be used to define a delegate. The delegate is used to create and configure the primary `HttpMessageHandler` used by that client: @@ -1221,13 +1206,6 @@ Header propagation is an ASP.NET Core middleware to propagate HTTP headers from var response = client.GetAsync(...); ``` -## Additional resources - -* [Use HttpClientFactory to implement resilient HTTP requests](/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests) -* [Implement HTTP call retries with exponential backoff with HttpClientFactory and Polly policies](/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly) -* [Implement the Circuit Breaker pattern](/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-circuit-breaker-pattern) -* [How to serialize and deserialize JSON in .NET](/dotnet/standard/serialization/system-text-json-how-to) - :::moniker-end :::moniker range="< aspnetcore-3.0" @@ -1268,7 +1246,7 @@ Once registered, code can accept an `IHttpClientFactory` anywhere services can b :::code language="csharp" source="http-requests/samples/2.x/HttpClientFactorySample/Pages/BasicUsage.cshtml.cs" id="snippet1" highlight="9-12,21"::: -Using `IHttpClientFactory` in this fashion is a good way to refactor an existing app. It has no impact on the way `HttpClient` is used. In places where `HttpClient` instances are currently created, replace those occurrences with a call to . +Using `IHttpClientFactory` in this fashion is a good way to refactor an existing app. It has no effect on the way `HttpClient` is used. In places where `HttpClient` instances are currently created, replace those occurrences with a call to . ### Named clients @@ -1391,7 +1369,7 @@ During registration, one or more handlers can be added to the configuration for In the preceding code, the `ValidateHeaderHandler` is registered with DI. The handler **must** be registered in DI as a transient service, never scoped. If the handler is registered as a scoped service and any services that the handler depends upon are disposable: * The handler's services could be disposed before the handler goes out of scope. -* The disposed handler services causes the handler to fail. +* The disposed handler services cause the handler to fail. Once registered, can be called, passing in the handler type. @@ -1426,7 +1404,7 @@ In the preceding code, a `WaitAndRetryAsync` policy is defined. Failed requests ### Dynamically select policies -Additional extension methods exist which can be used to add Polly-based handlers. One such extension is `AddPolicyHandler`, which has multiple overloads. One overload allows the request to be inspected when defining which policy to apply: +Other extension methods exist which can be used to add Polly-based handlers. One such extension is `AddPolicyHandler`, which has multiple overloads. One overload allows the request to be inspected when defining which policy to apply: :::code language="csharp" source="http-requests/samples/2.x/HttpClientFactorySample/Startup.cs" id="snippet8"::: @@ -1452,13 +1430,13 @@ Further information about `IHttpClientFactory` and Polly integrations can be fou ## HttpClient and lifetime management -A new `HttpClient` instance is returned each time `CreateClient` is called on the `IHttpClientFactory`. There's an per named client. The factory manages the lifetimes of the `HttpMessageHandler` instances. +A new `HttpClient` instance is returned each time `CreateClient` is called on the `IHttpClientFactory`. There's an for each named client. The factory manages the lifetimes of the `HttpMessageHandler` instances. -`IHttpClientFactory` pools the `HttpMessageHandler` instances created by the factory to reduce resource consumption. An `HttpMessageHandler` instance may be reused from the pool when creating a new `HttpClient` instance if its lifetime hasn't expired. +`IHttpClientFactory` pools the `HttpMessageHandler` instances created by the factory to reduce resource consumption. An `HttpMessageHandler` instance might be reused from the pool when creating a new `HttpClient` instance, if its lifetime isn't expired. Pooling of handlers is desirable as each handler typically manages its own underlying HTTP connections. Creating more handlers than necessary can result in connection delays. Some handlers also keep connections open indefinitely, which can prevent the handler from reacting to DNS changes. -The default handler lifetime is two minutes. The default value can be overridden on a per named client basis. To override it, call on the `IHttpClientBuilder` that is returned when creating the client: +The default handler lifetime is two minutes. The default value can be overridden on a per-named client basis. To override it, call on the `IHttpClientBuilder` that is returned when creating the client: :::code language="csharp" source="http-requests/samples/2.x/HttpClientFactorySample/Startup.cs" id="snippet11"::: @@ -1497,19 +1475,19 @@ Call extension method can be used to define a delegate. The delegate is used to create and configure the primary `HttpMessageHandler` used by that client: @@ -1547,10 +1525,20 @@ Header propagation is a community supported middleware to propagate HTTP headers var response = client.GetAsync(...); ``` -## Additional resources +:::moniker-end + +## Related content + +:::moniker range=">= aspnetcore-6.0" + +* [View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/http-requests/samples) ([how to download](xref:fundamentals/index#how-to-download-a-sample)) + +:::moniker-end * [Use HttpClientFactory to implement resilient HTTP requests](/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests) + * [Implement HTTP call retries with exponential backoff with HttpClientFactory and Polly policies](/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly) + * [Implement the Circuit Breaker pattern](/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-circuit-breaker-pattern) -:::moniker-end +* [How to serialize and deserialize JSON in .NET](/dotnet/standard/serialization/system-text-json-how-to) \ No newline at end of file diff --git a/aspnetcore/fundamentals/native-aot.md b/aspnetcore/fundamentals/native-aot.md index e3fd3e4d4914..3f904dc074f0 100644 --- a/aspnetcore/fundamentals/native-aot.md +++ b/aspnetcore/fundamentals/native-aot.md @@ -1,87 +1,90 @@ --- -title: ASP.NET Core support for Native AOT +title: ASP.NET Core Support for Native AOT author: tdykstra ms.author: tdykstra -description: Learn about ASP.NET Core support for Native AOT +description: Review ASP.NET Core support for Native ahead-of-time (AOT) applications, including publishing and deployment. +monikerRange: '>= aspnetcore-9.0' content_well_notification: AI-contribution ms.custom: mvc, engagement-fy23 -ms.date: 03/27/2025 +ms.date: 04/23/2026 uid: fundamentals/native-aot ai-usage: ai-assisted + +# ms.author: midenn (Mitch Denny) +# customer intent: As an ASP.NET developer, I want to explore ASP.NET Core support for Native AOT, so I can publish and deploy my Native AOT app. --- - # ASP.NET Core support for Native AOT By [Mitch Denny](https://github.com/mitchdenny) - -:::moniker range=">= aspnetcore-9.0" +Publishing and deploying Native ahead-of-time (AOT) applications in ASP.NET Core offers several benefits: -For Blazor WebAssembly Native AOT guidance, which adds to or supersedes the guidance in this article, see . +- **Minimized disk footprint**. When you publish an app by using Native AOT, the process produces a single executable file. The executable contains only the code from the external dependencies required to support the app. The reduced executable size can lead to: + * Smaller container images, for example in containerized deployment scenarios. + * Reduced deployment time from smaller images. -## Why use Native AOT with ASP.NET Core +- **Reduced startup time**. Native AOT apps can require less startup time, which enables: + * The app to service requests quicker. + * Improved deployment, where the container orchestrators manage the transition from one app version to another. -Publishing and deploying a Native AOT app provides the following benefits: +- **Reduced memory demand**. Native AOT apps can require less memory, depending on the work done by the app. Reduced memory consumption can lead to greater deployment density and improved scalability. -* **Minimized disk footprint**: When publishing using Native AOT, a single executable is produced containing just the code from external dependencies that is needed to support the program. Reduced executable size can lead to: - * Smaller container images, for example in containerized deployment scenarios. - * Reduced deployment time from smaller images. -* **Reduced startup time**: Native AOT applications can show reduced start-up times, which means - * The app is ready to service requests quicker. - * Improved deployment where container orchestrators need to manage transition from one version of the app to another. -* **Reduced memory demand**: Native AOT apps can have reduced memory demands, depending on the work done by the app. Reduced memory consumption can lead to greater deployment density and improved scalability. - -The template app was run in our benchmarking lab to compare performance of an AOT published app, a trimmed runtime app, and an untrimmed runtime app. The following chart shows the results of the benchmarking: - -![Chart showing comparison of application size, memory use, and startup time metrics of an AOT published app, a runtime app that is trimmed, and an untrimmed runtime app.](~/fundamentals/aot/_static/aot-runtime-trimmed-perf-chart.png) - -The preceding chart shows that Native AOT has lower app size, memory usage, and startup time. - -## ASP.NET Core and Native AOT compatibility - -Not all features in ASP.NET Core are currently compatible with Native AOT. The following table summarizes ASP.NET Core feature compatibility with Native AOT: - -| Feature | Fully Supported | Partially Supported | Not Supported | -| - | - | - | - | -| gRPC | Fully supported | | | -| Minimal APIs | | Partially supported | | -| MVC | | | Not supported | -| Blazor Server | | |Not supported | -| SignalR | | Partially supported | | -| JWT Authentication | Fully supported | | | -| Other Authentication | | | Not supported | -| CORS | Fully supported | | | -| HealthChecks | Fully supported | | | -| HttpLogging | Fully supported | | | -| Localization | Fully supported | | | -| OutputCaching | Fully supported | | | -| RateLimiting | Fully supported | | | -| RequestDecompression | Fully supported | | | -| ResponseCaching | Fully supported | | | -| ResponseCompression | Fully supported | | | -| Rewrite | Fully supported | | | -| Session | | |Not supported | -| Spa | | |Not supported | -| StaticFiles | Fully supported | | | -| WebSockets | Fully supported | | | +The following chart shows the results of a benchmarking test on the various template apps. The benchmark compares performance for an AOT published app (orange bar), a trimmed runtime app (green bar), and an untrimmed runtime app (yellow bar). The test revealed that the Native AOT app demonstrates lower app size, memory usage, and startup time. + +:::image type="content" source="~/fundamentals/aot/_static/aot-runtime-trimmed-perf-chart.png" border="false" alt-text="Chart showing a comparison of app size, memory use, and startup time metrics. The chart compares a published Native AOT app, a trimmed runtime app, and an untrimmed runtime app." + +This article describes support for Native AOT apps in ASP.NET Core, including an overview of publishing and deployment. + +For ASP.NET Core Blazor WebAssembly Native AOT guidance, which adds to or supersedes the guidance in this article, see [ASP.NET Core Blazor WebAssembly build tools and ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly). + +## Review ASP.NET Core and Native AOT compatibility + +Not all features in ASP.NET Core are currently compatible with Native AOT. + +The following table summarizes ASP.NET Core feature compatibility with Native AOT: + +| Feature | Supported | Partial support | Not supported | +|---|:---:|:---:|:---:| +| Blazor Server | | | ❌ | +| CORS | ✔️ | | | +| gRPC | ✔️ | | | +| HealthChecks | ✔️ | | | +| HttpLogging | ✔️ | | | +| JWT Authentication | ✔️ | | | +| Localization | ✔️ | | | +| Minimal APIs | | ✔️ | | +| MVC | | | ❌ | +| Other Authentication | | | ❌ | +| OutputCaching | ✔️ | | | +| RateLimiting | ✔️ | | | +| RequestDecompression | ✔️ | | | +| ResponseCaching | ✔️ | | | +| ResponseCompression | ✔️ | | | +| Rewrite | ✔️ | | | +| Session | | | ❌ | +| SignalR | | ✔️ | | +| Spa | | | ❌ | +| StaticFiles | ✔️ | | | +| WebSockets | ✔️ | | | For more information on limitations, see: * [Limitations of Native AOT deployment](/dotnet/core/deploying/native-aot#limitations-of-native-aot-deployment) -* [Introduction to AOT warnings](/dotnet/core/deploying/native-aot/fixing-warnings) +* [AOT warnings](/dotnet/core/deploying/native-aot/fixing-warnings) * [Known trimming incompatibilities](/dotnet/core/deploying/trimming/incompatibilities) -* [Introduction to trim warnings](/dotnet/core/deploying/trimming/fixing-warnings) -* [GitHub issue dotnet/core #8288](https://github.com/dotnet/core/issues/8288) +* [Fix trimming warnings](/dotnet/core/deploying/trimming/fixing-warnings) -It's important to test an app thoroughly when moving to a Native AOT deployment model. The AOT deployed app should be tested to verify functionality hasn't changed from the untrimmed and JIT-compiled app. When building the app, review and correct AOT warnings. An app that issues [AOT warnings](/dotnet/core/deploying/trimming/fixing-warnings) during publishing may not work correctly. If no AOT warnings are issued at publish time, the published AOT app should work the same as the untrimmed and JIT-compiled app. +### Verify app on the Native AOT deployment model -## Native AOT publishing +It's important to test an app thoroughly when you move to a Native AOT deployment model. Test the AOT deployed app and confirm the functionality is unchanged from the untrimmed and just-in-time (JIT) compiled app. -Native AOT is enabled with the `PublishAot` MSBuild property. The following example shows how to enable Native AOT in a project file: +When you build the app, review and correct any AOT warnings. An app that issues [AOT warnings](/dotnet/core/deploying/trimming/fixing-warnings) during publishing might not work correctly. If no AOT warnings are issued at publish time, you can expect the published AOT app to work the same as the untrimmed and JIT-compiled app. + +## Publish a Native AOT app (PublishAot) + +Enable Native AOT for your application by using the `PublishAot` MSBuild property. The following example shows how to enable Native AOT in a project file: ```xml @@ -89,35 +92,39 @@ Native AOT is enabled with the `PublishAot` MSBuild property. The following exam ``` -This setting enables Native AOT compilation during publish and enables dynamic code usage analysis during build and editing. A project that uses Native AOT publishing uses JIT compilation when running locally. An AOT app has the following differences from a JIT-compiled app: +The `PublishAot` property enables Native AOT compilation during the publish process, and enables dynamic code usage analysis during build and editing. A project that uses Native AOT publishing implements JIT compilation when it runs locally. + +An AOT app has the following differences from a JIT-compiled app: * Features that aren't compatible with Native AOT are disabled and throw exceptions at run time. * A source analyzer is enabled to highlight code that isn't compatible with Native AOT. At publish time, the entire app, including NuGet packages, are analyzed for compatibility again. -Native AOT analysis includes all of the app's code and the libraries the app depends on. Review Native AOT warnings and take corrective steps. It's a good idea to publish apps frequently to discover issues early in the development lifecycle. +Native AOT analysis includes all of the application code and the libraries the app depends on. Review Native AOT warnings and take corrective steps. It's a good idea to publish apps frequently to discover issues early in the development lifecycle. -In .NET 8, Native AOT is supported by the following ASP.NET Core app types: +In .NET 8 and later, the following ASP.NET Core app types support Native AOT: -* Minimal APIs - For more information, see the [The Web API (Native AOT) template](#the-web-api-native-aot-template) section later in this article. -* gRPC - For more information, see [gRPC and Native AOT](xref:grpc/native-aot). -* Worker services - For more information, see [AOT in Worker Service templates](xref:fundamentals/host/hosted-services?view=aspnetcore-8.0&preserve-view=true#native-aot). +* **Minimal APIs** - For more information, see [Review the Web API (Native AOT) template](#review-the-web-api-native-aot-template) later in this article. +* **gRPC** - For more information, see [gRPC and Native AOT](xref:grpc/native-aot). +* **Worker services** - For more information, see [Background tasks with hosted services in ASP.NET Core > Native AOT](xref:fundamentals/host/hosted-services#native-aot). -## The Web API (Native AOT) template +## Review the Web API (Native AOT) template -The **ASP.NET Core Web API (Native AOT)** template (short name `webapiaot`) creates a project with AOT enabled. The template differs from the **Web API** project template in the following ways: +The ASP.NET Core **Web API (Native AOT)** template (short name `webapiaot`) creates a project with AOT enabled. The template differs from a standard **Web API** project template in the following ways: * Uses Minimal APIs only, as MVC isn't yet compatible with Native AOT. -* Uses the API to ensure only the essential features are enabled by default, minimizing the app's deployed size. -* Is configured to listen on HTTP only, as HTTPS traffic is commonly handled by an ingress service in cloud-native deployments. +* Uses the API to ensure only the essential features are enabled by default, which minimizes the app's deployed size. +* Is configured to listen on HTTP only. HTTPS traffic is commonly handled by an ingress service in cloud-native deployments. * Doesn't include a launch profile for running under IIS or IIS Express. -* Creates an [`.http` file](xref:test/http-files) configured with sample HTTP requests that can be sent to the app's endpoints. +* Creates an [.http file](xref:test/http-files) configured with sample HTTP requests that can be sent to the app's endpoints. * Includes a sample `Todo` API instead of the weather forecast sample. -* Adds `PublishAot` to the project file, as shown [earlier in this article](#native-aot-publishing). +* Adds the `PublishAot` property to the project file, as [described earlier](#publish-a-native-aot-app-publishaot). * Enables the [JSON serializer source generators](/dotnet/standard/serialization/system-text-json/source-generation). The source generator is used to generate serialization code at build time, which is required for Native AOT compilation. -### Changes to support source generation +### Code updates for JSON serialization (Program.cs) + +The code in the _Program.cs_ file is modified to provide support for JSON serialization source generation. -The following example shows the code added to the `Program.cs` file to support JSON serialization source generation: +The following snippet shows the changes to the code: ```diff using MyFirstAotWebApi; @@ -151,16 +158,18 @@ app.Run(); +} ``` -Without this added code, `System.Text.Json` uses reflection to serialize and deserialize JSON. Reflection isn't supported in Native AOT. +If you don't modify the code, `System.Text.Json` uses reflection to serialize and deserialize JSON. Reflection isn't supported in Native AOT. For more information, see: -* [Combine source generators](/dotnet/standard/serialization/system-text-json/source-generation?pivots=dotnet-8-0#combine-source-generators) +* [Combine source generators](/dotnet/standard/serialization/system-text-json/source-generation#combine-source-generators) * -### Changes to `launchSettings.json` +### Code changes for launch profile (launchSettings.json) -The `launchSettings.json` file created by the **Web API (Native AOT)** template has the `iisSettings` section and `IIS Express` profile removed: +The **Web API (Native AOT)** template creates a _launchSettings.json_ file. In contrast to a standard launch file, the generated file doesn't include the `iisSettings` section or the `IIS Express` profile. + +The following snippet shows the excluded sections (colored red): ```diff { @@ -196,112 +205,102 @@ The `launchSettings.json` file created by the **Web API (Native AOT)** template } ``` - - -### The `CreateSlimBuilder` method +### CreateSlimBuilder() called for minimal app defaults -The template uses the method instead of the method. +The **Web API (Native AOT)** template uses the method instead of the method. :::code language="csharp" source="~/fundamentals/aot/samples/Program.cs" highlight="4"::: The `CreateSlimBuilder` method initializes 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](/dotnet/api/microsoft.aspnetcore.hosting.webhostbuilderkestrelextensions.usekestrelhttpsconfiguration) HTTP/3 can be enabled by calling [builder.WebHost.UseQuic](xref:Microsoft.AspNetCore.Hosting.WebHostBuilderQuicExtensions.UseQuic%2A). +As described 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). You can enable HTTPS by calling the +[builder.WebHost.UseKestrelHttpsConfiguration](/dotnet/api/microsoft.aspnetcore.hosting.webhostbuilderkestrelextensions.usekestrelhttpsconfiguration) method, or enable HTTP/3 by calling the [builder.WebHost.UseQuic](xref:Microsoft.AspNetCore.Hosting.WebHostBuilderQuicExtensions.UseQuic%2A). -### `CreateSlimBuilder` vs `CreateBuilder` +## Compare CreateSlimBuilder() and CreateBuilder() -The `CreateSlimBuilder` method doesn't support the following features that are supported by the `CreateBuilder` method: +The `CreateSlimBuilder` method provides access to a portion of the application features available with the `CreateBuilder` method. As described earlier, the **Web API (Native AOT)** template calls `CreateSlimBuilder` to initialize , so the builder uses the minimum ASP.NET Core features necessary to run the app. -* [Hosting startup assemblies](xref:fundamentals/configuration/platform-specific-configuration) -* -* The following logging providers: - * [Windows EventLog](/aspnet/core/fundamentals/logging#windows-eventlog) - * [Debug](/aspnet/core/fundamentals/logging#debug) - * [Event Source](/aspnet/core/fundamentals/logging#event-source) -* Web hosting features: - * - * [IIS Integration](xref:host-and-deploy/iis/index) -* Kestrel configuration - * [HTTPS endpoints in Kestrel](xref:fundamentals/servers/kestrel/endpoints#https) - * [Quic (HTTP/3)](xref:fundamentals/servers/kestrel/http3#http3-benefits) -* [Regex and alpha constraints used in routing](https://github.com/dotnet/aspnetcore/issues/46142) +Both methods provide the necessary features for an efficient development experience: -The `CreateSlimBuilder` method includes the following features needed for an efficient development experience: +* Configuration for the _appsettings.json_ and _appsettings.{EnvironmentName}.json_ files +* User secrets configuration +* Console logging +* Logging configuration -* JSON file configuration for `appsettings.json` and `appsettings.{EnvironmentName}.json`. -* User secrets configuration. -* Console logging. -* Logging configuration. +Including minimal features has benefits for trimming as well as AOT. For more information, see [Trim self-contained deployments and executables](/dotnet/core/deploying/trimming/trim-self-contained). -For a builder that omits the preceding features, see [The `CreateEmptyBuilder` method](xref:aspnetcore-8#new-createemptybuilder-method). +If you prefer to use a builder that omits all features, see the [WebApplication.CreateEmptyBuilder](/dotnet/api/microsoft.aspnetcore.builder.webapplication.createemptybuilder) method. -Including minimal features has benefits for trimming as well as AOT. For more information, see [Trim self-contained deployments and executables](/dotnet/core/deploying/trimming/trim-self-contained). +### Unavailable features in CreateSlimBuilder -For more detailed information, see [Comparing `WebApplication.CreateBuilder` to `CreateSlimBuilder`](https://andrewlock.net/exploring-the-dotnet-8-preview-comparing-createbuilder-to-the-new-createslimbuilder-method/) +The `CreateSlimBuilder` method **doesn't** provide the following features, which are available in `CreateBuilder`: -## Source generators +* [Hosting startup assemblies](xref:fundamentals/configuration/platform-specific-configuration) +* [UseStartup](xref:Microsoft.AspNetCore.Hosting.WebHostBuilderExtensions.UseStartup%2A) method +* Logging providers: + * [Windows EventLog](/aspnet/core/fundamentals/logging#windows-eventlog) + * [Debug](/aspnet/core/fundamentals/logging#debug) + * [EventSource](/aspnet/core/fundamentals/logging#eventsource) +* Web hosting features: + * [UseStaticWebAssets](xref:Microsoft.AspNetCore.Hosting.WebHostBuilderExtensions.UseStaticWebAssets%2A) method + * [IIS integration](xref:host-and-deploy/iis/index) +* Kestrel configuration: + * [HTTPS endpoints](xref:fundamentals/servers/kestrel/endpoints#configure-https) + * [QUIC (HTTP/3)](xref:fundamentals/servers/kestrel/http3#http3-benefits) +* [Regex and alpha constraints used in routing (GitHub /dotnet/aspnetcore/issues #46142)](https://github.com/dotnet/aspnetcore/issues/46142) -Because unused code is trimmed during publishing for Native AOT, the app can't use unbounded reflection at runtime. [Source generators](/dotnet/csharp/roslyn-sdk/source-generators-overview) are used to produce code that avoids the need for reflection. In some cases, source generators produce code optimized for AOT even when a generator isn't required. +For more detailed information, see [Comparing WebApplication.CreateBuilder to CreateSlimBuilder](https://andrewlock.net/exploring-the-dotnet-8-preview-comparing-createbuilder-to-the-new-createslimbuilder-method/) -To view the source code that is generated, add the [`EmitCompilerGeneratedFiles`](/dotnet/csharp/roslyn-sdk/source-generators-overview) property to an app's `.csproj` file, as shown in the following example: +## Use source generators and avoid reflection -```xml - +During the publishing process for Native AOT, any unused code is trimmed. As a result, an app can't use unbounded reflection at runtime. You can use [source generators](/dotnet/csharp/roslyn-sdk/#source-generators) that produce code that avoids the need for reflection. In some cases, source generators output code optimized for AOT even when a generator isn't required. - - - true - +- To view the generated source code, add the [EmitCompilerGeneratedFiles](/dotnet/core/extensions/configuration-generator) property to the application project (_.csproj_) file: - -``` + ```xml + + + + + true + + + + ``` -Run the `dotnet build` command to see the generated code. The output includes an `obj/Debug/net8.0/generated/` directory that contains all the generated files for the project. +- To see the generated code, run the `dotnet build` command. The command compiles the source files and generates the intermediate files needed to run the app in a development environment. The output includes an _obj/Debug/<.NET version>/generated/_ directory that contains all the generated files for the project. -The `dotnet publish` command also compiles the source files and generates files that are compiled. In addition, `dotnet publish` passes the generated assemblies to a native IL compiler. The IL compiler produces the native executable. The native executable contains the native machine code. +- To prepare the app for deployment, run the `dotnet publish` command. The command compiles the source files and generates all files required to deploy the app. It passes the generated assemblies to a native IL compiler, which produces the native executable. The native executable contains the native machine code. [!INCLUDE[](~/fundamentals/aot/includes/aot_lib.md)] -## Minimal APIs and JSON payloads +## Work with Minimal APIs and JSON payloads -The Minimal API framework is optimized for receiving and returning JSON payloads using . `System.Text.Json`: +The Minimal API framework is optimized for receiving and returning JSON payloads by using the . -* Imposes compatibility requirements for JSON and Native AOT. -* Requires the use of the [`System.Text.Json` source generator](/dotnet/standard/serialization/system-text-json/source-generation). +* The namespace imposes compatibility requirements for JSON and Native AOT. +* It requires the use of the [System.Text.Json source generator](/dotnet/standard/serialization/system-text-json/source-generation). -All types that are transmitted as part of the HTTP body or returned from request delegates in Minimal APIs apps must be configured on a that is registered via ASP.NET Core’s dependency injection: +All types transmitted as part of the HTTP body or returned from request delegates in Minimal APIs apps must be configured on a instance. The instance must be registered with ASP.NET Core dependency injection: :::code language="csharp" source="~/fundamentals/aot/samples/Program.cs" highlight="7-10,25-99"::: -In the preceding highlighted code: +* The JSON serializer context is registered with the [DI container](xref:fundamentals/dependency-injection). For more information, see [Combine source generators](/dotnet/standard/serialization/system-text-json/source-generation#combine-source-generators) and the . -* The JSON serializer context is registered with the [DI container](xref:fundamentals/dependency-injection). For more information, see: - * [Combine source generators](/dotnet/standard/serialization/system-text-json/source-generation?pivots=dotnet-8-0#combine-source-generators) - * -* The custom `JsonSerializerContext` is annotated with the [`[JsonSerializable]`](/dotnet/api/system.text.json.serialization.jsonserializableattribute) attribute to enable source generated JSON serializer code for the `ToDo` type. +* The custom `JsonSerializerContext` is annotated with the [JsonSerializable](/dotnet/api/system.text.json.serialization.jsonserializableattribute) attribute, which enables source generated JSON serializer code for the `ToDo` type. -A parameter on the delegate that isn't bound to the body and does ***not*** need to be serializable. For example, a query string parameter that is a rich object type and implements `IParsable`. +A parameter on the delegate that isn't bound to the body and **doesn't** need to be serializable. For example, a query string parameter that's a rich object type and implements `IParsable`. :::code language="csharp" source="~/fundamentals/aot/samples/Todo.cs" id="snippet_1"::: -## Known issues +## Review known issues -See [this GitHub issue](https://github.com/dotnet/core/issues/8288) to report or review issues with Native AOT support in ASP.NET Core. +To report or review issues with Native AOT support in ASP.NET Core, see [GitHub /dotnet/core/issues #8288)](https://github.com/dotnet/core/issues/8288). -## See also +## Related content -* +* [Publish an ASP.NET Core app with Native AOT](xref:fundamentals/native-aot-tutorial) * [Native AOT deployment](/dotnet/core/deploying/native-aot/) * [Optimize AOT deployments](/dotnet/core/deploying/native-aot/optimizing) -* [Configuration-binding source generator](/dotnet/core/whats-new/dotnet-8#configuration-binding-source-generator) -* [Using the configuration binder source generator](https://andrewlock.net/exploring-the-dotnet-8-preview-using-the-new-configuration-binder-source-generator/) -* [The Minimal API AOT compilation template](https://andrewlock.net/exploring-the-dotnet-8-preview-the-minimal-api-aot-template/) -* [Comparing `WebApplication.CreateBuilder` to `CreateSlimBuilder`](https://andrewlock.net/exploring-the-dotnet-8-preview-comparing-createbuilder-to-the-new-createslimbuilder-method/) -* [Exploring the new Minimal API source generator](https://andrewlock.net/exploring-the-dotnet-8-preview-exploring-the-new-minimal-api-source-generator/) -* [Replacing method calls with Interceptors](https://andrewlock.net/exploring-the-dotnet-8-preview-changing-method-calls-with-interceptors/) -* [Behind `[LogProperties]` and the new telemetry logging source generator](https://andrewlock.net/behind-logproperties-and-the-new-telemetry-logging-source-generator/) - -:::moniker-end [!INCLUDE[](~/fundamentals/native-aot/includes/native-aot8.md)] diff --git a/aspnetcore/fundamentals/servers/kestrel/endpoints.md b/aspnetcore/fundamentals/servers/kestrel/endpoints.md index 2a7fac4c9c48..54d0fd2dbfc5 100644 --- a/aspnetcore/fundamentals/servers/kestrel/endpoints.md +++ b/aspnetcore/fundamentals/servers/kestrel/endpoints.md @@ -1,93 +1,82 @@ --- -title: Configure endpoints for the ASP.NET Core Kestrel web server +title: Configure Endpoints for Kestrel Web Server author: tdykstra description: Learn about configuring endpoints with Kestrel, the cross-platform web server for ASP.NET Core. -monikerRange: '>= aspnetcore-5.0' +monikerRange: '>= aspnetcore-8.0' ms.author: tdykstra ms.custom: mvc -ms.date: 03/05/2025 +ms.date: 04/23/2026 uid: fundamentals/servers/kestrel/endpoints + +#customer intent: As an ASP.MEt developer, I want to configure endpoints with Kestrel, so I can use a Kestrel web server with my ASP.NET Core app. --- # Configure endpoints for the ASP.NET Core Kestrel web server [!INCLUDE[](~/includes/not-latest-version.md)] -:::moniker range=">= aspnetcore-8.0" - Kestrel endpoints provide the infrastructure for listening to incoming requests and routing them to the appropriate middleware. The combination of an address and a protocol defines an endpoint. * The address specifies the network interface that the server listens on for incoming requests, such as a TCP port. * The protocol specifies the communication between the client and server, such as HTTP/1.1, HTTP/2, or HTTP/3. -* An endpoint can be secured using the `https` URL scheme or `UseHttps` method. - -Endpoints can be configured using URLs, JSON in `appsettings.json`, and code. This article discusses how to use each option to configure an endpoint: +* An endpoint can be secured by using the `https` URL scheme or `UseHttps` method. -* [Configure endpoints](#configure-endpoints) -* [Configure HTTPS](#configure-https) -* [Configure HTTP protocols](#configure-http-protocols) +Endpoints can be configured with URLs, JSON in the _appsettings.json_ file, and code. This article describes how to use each option to configure endpoints, HTTPS, and HTTP protocols. -## Default endpoint +## Identify the default endpoint -New ASP.NET Core projects are configured to bind to a random HTTP port between 5000-5300 and a random HTTPS port between 7000-7300. The selected ports are stored in the generated `Properties/launchSettings.json` file and can be modified by the developer. The `launchSetting.json` file is only used in local development. +The configuration for new ASP.NET Core projects binds each project to a default endpoint. The configuration selects a random HTTP port between 5000-5300 and a random HTTPS port between 7000-7300. The selected ports are stored in the generated _Properties/launchSettings.json_ file and are modifiable by the developer. The _launchSetting.json_ file is used for local development only. -If there's no endpoint configuration, then Kestrel binds to `http://localhost:5000`. +If there's no endpoint configuration, Kestrel binds to the `http://localhost:5000` URL. ## Configure endpoints -Kestrel endpoints listen for incoming connections. When an endpoint is created, it must be configured with the address it will listen to. Usually, this is a TCP address and port number. +Kestrel endpoints listen for incoming connections. When an endpoint is created, it must be configured with the address to use for listening. The address is usually a TCP address and port number. -There are several options for configuring endpoints: +You have several options for configuring endpoints. You can specify the URLs or ports directly, define the addresses in your code, or create the endpoints with JSON in the _appsettings.json_ file. -* [Configure endpoints with URLs](#configure-endpoints-with-urls) -* [Specify ports only](#specify-ports-only) -* [Configure endpoints in appsettings.json](#configure-endpoints-in-appsettingsjson) -* [Configure endpoints in code](#configure-endpoints-in-code) +### Specify endpoints with URLs -### Configure endpoints with URLs +The following sections explain how to configure endpoints by using the following resources: -The following sections explain how to configure endpoints using the: - -* `ASPNETCORE_URLS` environment variable. -* `--urls` command-line argument. -* `urls` host configuration key. -* extension method. -* property. +* `ASPNETCORE_URLS` environment variable +* `--urls` command-line argument +* `urls` host configuration key +* [UseUrls](xref:Microsoft.AspNetCore.Hosting.HostingAbstractionsWebHostBuilderExtensions.UseUrls%2A) extension method +* [WebApplication.Urls](xref:Microsoft.AspNetCore.Builder.WebApplication.Urls) property #### URL formats -The URLs indicate the IP or host addresses with ports and protocols the server should listen on. The port can be omitted if it's the default for the protocol (typically 80 and 443). URLs can be in any of the following formats. +The URLs indicate the IP or host addresses with ports and protocols that the server listens on. You can omit the port if it's the default for the protocol (typically 80 and 443). URLs can be in any of the following formats. -* IPv4 address with port number +* IPv4 address with port number: - ``` + ```url http://65.55.39.10:80/ ``` `0.0.0.0` is a special case that binds to all IPv4 addresses. -* IPv6 address with port number +* IPv6 address with port number: - ``` + ```url http://[0:0:0:0:0:ffff:4137:270a]:80/ ``` `[::]` is the IPv6 equivalent of IPv4 `0.0.0.0`. -* Wildcard host with port number +* Wildcard (`*`) host with port number: - ``` + ```url http://contoso.com:80/ http://*:80/ ``` - Anything not recognized as a valid IP address or `localhost` is treated as a wildcard that binds to all IPv4 and IPv6 addresses. Some people like to use `*` or `+` to be more explicit. To bind different host names to different ASP.NET Core apps on the same port, use [HTTP.sys](xref:fundamentals/servers/httpsys) or a reverse proxy server. - - Reverse proxy server examples include IIS, YARP, Nginx, and Apache. + Anything not recognized as a valid IP address or `localhost` is treated as a wildcard that binds to all IPv4 and IPv6 addresses. Some developers prefer to use the asterisk `*` or plus symbol `+` to be more explicit. To bind different host names to different ASP.NET Core apps on the same port, use [HTTP.sys](xref:fundamentals/servers/httpsys) or a reverse proxy server. Reverse proxy server examples include IIS, YARP, Nginx, and Apache. -* Host name `localhost` with port number or loopback IP with port number +* Host name `localhost` with port number or loopback IP with port number: - ``` + ```url http://localhost:5000/ http://127.0.0.1:5000/ http://[::1]:5000/ @@ -95,25 +84,23 @@ The URLs indicate the IP or host addresses with ports and protocols the server s When `localhost` is specified, Kestrel attempts to bind to both IPv4 and IPv6 loopback interfaces. If the requested port is in use by another service on either loopback interface, Kestrel fails to start. If either loopback interface is unavailable for any other reason (most commonly because IPv6 isn't supported), Kestrel logs a warning. -Multiple URL prefixes can be specified by using a semicolon (`;`) delimiter: +* Specify multiple URL prefixes by using a semicolon (`;`) delimiter, for example: -``` -http://*:5000;http://localhost:5001;https://hostname:5002 -``` + ```url + http://*:5000;http://localhost:5001;https://hostname:5002 + ``` For more information, see [Override configuration](xref:fundamentals/host/web-host#override-configuration). #### HTTPS URL prefixes -HTTPS URL prefixes can be used to define endpoints only if a default certificate is provided in the HTTPS endpoint configuration. For example, use configuration or a configuration file, as shown [later in this article](#configure-https-in-appsettingsjson). - -For more information, see [Configure HTTPS](#configure-https). +You can define endpoints by using HTTPS URL prefixes only if a default certificate is provided in the HTTPS endpoint configuration. For example, use the configuration or a configuration file. This approach is described in the [Configure HTTPS in appsettings.json](#configure-https-in-appsettingsjson) section later in this article. For more information, see the [Configure HTTPS](#configure-https) section. ### Specify ports only [!INCLUDE [http-ports](~/includes/http-ports.md)] -### Configure endpoints in appsettings.json +### Create endpoints in appsettings.json Kestrel can load endpoints from an instance. By default, Kestrel configuration is loaded from the `Kestrel` section and endpoints are configured in `Kestrel:Endpoints`: @@ -129,38 +116,38 @@ Kestrel can load endpoints from an . +By default, the endpoint configuration can be reloaded when the configuration source changes. It can be disabled by using the method. -If a change is signaled, the following steps are taken: +When a change is signaled: -* The new configuration is compared to the old one, and any endpoint without configuration changes isn't modified. -* Removed or modified endpoints are given 5 seconds to complete processing requests and shut down. +* The new configuration is compared to the old version. Any endpoint without configuration changes isn't modified. +* Removed or modified endpoints are allowed 5 seconds to complete processing requests and shut down. * New or modified endpoints are started. -Clients connecting to a modified endpoint may be disconnected or refused while the endpoint is restarted. +Clients connecting to a modified endpoint might be disconnected or refused while the endpoint is restarted. #### ConfigurationLoader - returns a . The loader's method that can be used to supplement a configured endpoint's settings: +The returns a . The loader's method can be used to supplement a configured endpoint's settings: :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_ConfigurationLoader"::: -`KestrelServerOptions.ConfigurationLoader` can be directly accessed to continue iterating on the existing loader, such as the one provided by . +`KestrelServerOptions.ConfigurationLoader` can be directly accessed to continue iterating on the existing loader, such as the one provided by the . -* The configuration section for each endpoint is available on the options in the method so that custom settings may be read. -* can be called multiple times, but only the last configuration is used unless `Load` is explicitly called on prior instances. The default host doesn't call `Load` so that its default configuration section may be replaced. +* The configuration section for each endpoint is available on the options in the method so custom settings can be read. +* can be called multiple times, but only the last configuration is used unless `Load` is explicitly called on prior instances. The default host doesn't call `Load` so its default configuration section might be replaced. * `KestrelConfigurationLoader` mirrors the `Listen` family of APIs from `KestrelServerOptions` as `Endpoint` overloads, so code and config endpoints can be configured in the same place. These overloads don't use names and only consume default settings from configuration. -### Configure endpoints in code +### Define endpoints in the code provides methods for configuring endpoints in code: @@ -170,7 +157,7 @@ Clients connecting to a modified endpoint may be disconnected or refused while t * * -When both the `Listen` and [UseUrls](#configure-endpoints-with-urls) APIs are used simultaneously, the `Listen` endpoints override the `UseUrls` endpoints. +When both the `Listen` and [UseUrls](#specify-endpoints-with-urls) APIs are used simultaneously, the `Listen` endpoints override the `UseUrls` endpoints. #### Bind to a TCP socket @@ -178,10 +165,10 @@ The extension method on . For more information, see [Configure HTTPS in code](#configure-https-in-code). +* Configures HTTPS for an endpoint with the extension method on a object. For more information, see [Configure HTTPS in code](#configure-https-in-code). [!INCLUDE [How to make an X.509 cert](~/includes/make-x509-cert.md)] @@ -191,38 +178,37 @@ Listen on a Unix socket with `location` > `proxy_pass` entry to `http://unix:/tmp/{KESTREL SOCKET}:/;`. `{KESTREL SOCKET}` is the name of the socket provided to (for example, `kestrel-test.sock` in the preceding example). -* Ensure that the socket is writeable by Nginx (for example, `chmod go+w /tmp/kestrel-test.sock`). +* In the Nginx configuration file, set the `server` > `location` > `proxy_pass` entry to `http://unix:/tmp/{KESTREL SOCKET}:/;`, where `{KESTREL SOCKET}` is the name of the socket provided to . In the code exmaple, the name is `kestrel-test.sock`. +* Ensure the socket is writeable by Nginx. (You can set the write permissions on the socket with the `chmod go+w /tmp/kestrel-test.sock` command). #### Configure endpoint defaults -[`ConfigureEndpointDefaults(Action)`](xref:Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.ConfigureEndpointDefaults(System.Action{Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions})) specifies configuration that runs for each specified endpoint. Calling `ConfigureEndpointDefaults` multiple times replaces previous configuration. +[ConfigureEndpointDefaults(Action\)](xref:Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.ConfigureEndpointDefaults(System.Action{Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions})) specifies configuration that runs for each specified endpoint. Multiple calls to `ConfigureEndpointDefaults` replace the previous configuration. :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_ConfigureEndpointDefaults"::: > [!NOTE] -> Endpoints created by calling **before** calling won't have the defaults applied. +> Endpoints created by calling the **before** calling the don't have the defaults applied. -### Dynamic port binding +### Use dynamic port binding -When port number `0` is specified, Kestrel dynamically binds to an available port. The following example shows how to determine which port Kestrel bound at runtime: +When port number `0` is specified, Kestrel dynamically binds to an available port. The following example shows how to determine the port bound by Kestrel at runtime: :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_IServerAddressesFeature"::: -Dynamically binding a port isn't available in some situations: +Dynamically binding a port isn't available in some scenarios: -* -* Binding TCP-based HTTP/1.1 or HTTP/2, and QUIC-based HTTP/3 together. +* The code calls the . +* The code binds together TCP-based HTTP/1.1 or HTTP/2 with QUIC-based HTTP/3. ## Configure HTTPS -Kestrel supports securing endpoints with HTTPS. Data sent over HTTPS is encrypted using [Transport Layer Security (TLS)](https://tools.ietf.org/html/rfc5246) to increase the security of data transferred between the client and server. +Kestrel supports securing endpoints with HTTPS. Data sent over HTTPS is encrypted by using [Transport Layer Security (TLS)](https://tools.ietf.org/html/rfc5246) to increase the security of data transferred between the client and server. HTTPS requires a TLS certificate. The TLS certificate is stored on the server, and Kestrel is configured to use it. An app can use the [ASP.NET Core HTTPS development certificate](xref:security/enforcing-ssl) in a local development environment. The development certificate isn't installed in nondevelopment environments. In production, a TLS certificate must be explicitly configured. At a minimum, a default certificate must be provided. -The way HTTPS and the TLS certificate is configured depends on how endpoints are configured: +How HTTPS and the TLS certificate is configured depends on how endpoints are configured. If [URL prefixes](#specify-endpoints-with-urls) or [only specified ports](#specify-ports-only) are used to define endpoints, HTTPS can be used only if a default certificate is provided in HTTPS endpoint configuration. A default certificate can be configured with the following options: -* If [URL prefixes](#configure-endpoints-with-urls) or [specify ports only](#specify-ports-only) are used to define endpoints, HTTPS can be used only if a default certificate is provided in HTTPS endpoint configuration. A default certificate can be configured with one of the following options: * [Configure HTTPS in appsettings.json](#configure-https-in-appsettingsjson) * [Configure HTTPS in code](#configure-https-in-code) @@ -230,9 +216,9 @@ The way HTTPS and the TLS certificate is configured depends on how endpoints are A default HTTPS app settings configuration schema is available for Kestrel. Configure multiple endpoints, including the URLs and the certificates to use, either from a file on disk or from a certificate store. -Any HTTPS endpoint that doesn't specify a certificate (`HttpsDefaultCert` in the example that follows) falls back to the certificate defined under `Certificates:Default` or the development certificate. +Any HTTPS endpoint that doesn't specify a certificate (`HttpsDefaultCert` in the following example code) falls back to the certificate defined under `Certificates:Default` or the development certificate. -The following example is for `appsettings.json`, but any configuration source can be used: +The following example is for the _appsettings.json_ file, but any configuration source can be used: ```json { @@ -284,21 +270,21 @@ The following example is for `appsettings.json`, but any configuration source ca #### Schema notes * Endpoint names are [case-insensitive](xref:fundamentals/configuration/index#configuration-keys-and-values). For example, `HTTPS` and `Https` are equivalent. -* The `Url` parameter is required for each endpoint. The format for this parameter is the same as the top-level `Urls` configuration parameter except that it's limited to a single value. See [URL formats](#url-formats) earlier in this article. -* These endpoints replace the ones defined in the top-level `Urls` configuration rather than adding to them. Endpoints defined in code via `Listen` are cumulative with the endpoints defined in the configuration section. +* The `Url` parameter is required for each endpoint. The format for this parameter is the same as the top-level `Urls` configuration parameter, but it can have only a single value. For more information, see the [URL formats](#url-formats) section in this article. +* These endpoints replace the values defined in the top-level `Urls` configuration rather than adding to them. Endpoints defined in code with the `Listen` API are cumulative with the endpoints defined in the configuration section. * The `Certificate` section is optional. If the `Certificate` section isn't specified, the defaults defined in `Certificates:Default` are used. If no defaults are available, the development certificate is used. If there are no defaults and the development certificate isn't present, the server throws an exception and fails to start. * The `Certificate` section supports multiple certificate sources. -* Any number of endpoints may be defined in `Configuration`, as long as they don't cause port conflicts. +* Any number of endpoints can be defined in `Configuration`, as long as they don't cause port conflicts. #### Certificate sources -Certificate nodes can be configured to load certificates from a number of sources: +Certificate nodes can be configured to load certificates from various sources: -* `Path` and `Password` to load *.pfx* files. -* `Path`, `KeyPath` and `Password` to load *.pem*/*.crt* and *.key* files. -* `Subject` and `Store` to load from the certificate store. +* `Path` and `Password`: Load _.pfx_ files. +* `Path`, `KeyPath`, and `Password`: Load _.pem_/_.crt_ and _.key_ files. +* `Subject` and `Store`: Load from the certificate store. -For example, the `Certificates:Default` certificate can be specified as: +For example, the `Certificates:Default` certificate can be specified with the following JSON: ```json "Default": { @@ -311,7 +297,7 @@ For example, the `Certificates:Default` certificate can be specified as: #### Configure client certificates in appsettings.json -[ClientCertificateMode](xref:Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode) is used to configure client certificate behavior. +The [ClientCertificateMode](xref:Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode) is used to configure client certificate behavior. ```json { @@ -334,11 +320,11 @@ For example, the `Certificates:Default` certificate can be specified as: The default value is `ClientCertificateMode.NoCertificate`, where Kestrel doesn't request or require a certificate from the client. -For more information, see . +For more information, see [Configure certificate authentication in ASP.NET Core](xref:security/authentication/certauth). #### Configure SSL/TLS protocols in appsettings.json -SSL Protocols are protocols used for encrypting and decrypting traffic between two peers, traditionally a client and a server. +SSL Protocols are protocols used for encrypting and decrypting traffic between two peers, which traditionally are a client and a server. ```json { @@ -363,51 +349,51 @@ The default value, `SslProtocols.None`, causes Kestrel to use the operating syst ### Configure HTTPS in code -When using the `Listen` API, the extension method on is available to configure HTTPS. +When you use the `Listen` API, the extension method on is available to configure HTTPS. :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_Listen"::: -`ListenOptions.UseHttps` parameters: +The `ListenOptions.UseHttps` parameters include: -* `filename` is the path and file name of a certificate file, relative to the directory that contains the app's content files. -* `password` is the password required to access the X.509 certificate data. -* `configureOptions` is an `Action` to configure the `HttpsConnectionAdapterOptions`. Returns the `ListenOptions`. -* `storeName` is the certificate store from which to load the certificate. -* `subject` is the subject name for the certificate. -* `allowInvalid` indicates if invalid certificates should be considered, such as self-signed certificates. -* `location` is the store location to load the certificate from. -* `serverCertificate` is the X.509 certificate. +* `filename`: The path and file name of a certificate file, relative to the directory that contains the app's content files. +* `password`: The password required to access the X.509 certificate data. +* `configureOptions`: An `Action` to configure the `HttpsConnectionAdapterOptions`. Returns the `ListenOptions`. +* `storeName`: The certificate store from which to load the certificate. +* `subject`: The subject name for the certificate. +* `allowInvalid`: Indicates whether to consider invalid certificates, such as self-signed certificates. +* `location`: The store location to load the certificate from. +* `serverCertificate`: The X.509 certificate. For a complete list of `UseHttps` overloads, see . #### Configure client certificates in code - configures the client certificate requirements. +The configures the client certificate requirements. :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_ConfigureHttpsDefaultsClientCertificateMode"::: -The default value is , where Kestrel doesn't request or require a certificate from the client. +The default value is (0), where Kestrel doesn't request or require a certificate from the client. -For more information, see . +For more information, see [Configure certificate authentication in ASP.NET Core](xref:security/authentication/certauth). #### Configure HTTPS defaults in code -[ConfigureHttpsDefaults(Action\)](xref:Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.ConfigureHttpsDefaults(System.Action{Microsoft.AspNetCore.Server.Kestrel.Https.HttpsConnectionAdapterOptions})) specifies a configuration `Action` to run for each HTTPS endpoint. Calling `ConfigureHttpsDefaults` multiple times replaces prior `Action` instances with the last `Action` specified. +The [ConfigureHttpsDefaults(Action\)](xref:Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.ConfigureHttpsDefaults(System.Action{Microsoft.AspNetCore.Server.Kestrel.Https.HttpsConnectionAdapterOptions})) specifies a configuration `Action` to run for each HTTPS endpoint. Multiple calls to `ConfigureHttpsDefaults` replace prior `Action` instances with the last `Action` specified. :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_ConfigureHttpsDefaults"::: > [!NOTE] -> Endpoints created by calling **before** calling won't have the defaults applied. +> Endpoints created by calling the **before** calling the don't have the defaults applied. #### Configure SSL/TLS protocols in code -SSL protocols are protocols used for encrypting and decrypting traffic between two peers, traditionally a client and a server. +SSL protocols are protocols used for encrypting and decrypting traffic between two peers, which traditionally are a client and a server. :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_ConfigureHttpsDefaultsSslProtocols"::: #### Configure TLS cipher suites filter in code -On Linux, can be used to filter TLS handshakes on a per-connection basis: +On Linux, a object can be used to filter TLS handshakes on a per-connection basis: :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_ConfigureHttpsDefaultsCipherSuitesPolicy"::: @@ -415,14 +401,14 @@ On Linux, can be used to filter TL [Server Name Indication (SNI)](https://tools.ietf.org/html/rfc6066#section-3) can be used to host multiple domains on the same IP address and port. SNI can be used to conserve resources by serving multiple sites from one server. -For SNI to function, the client sends the host name for the secure session to the server during the TLS handshake so that the server can provide the correct certificate. The client uses the furnished certificate for encrypted communication with the server during the secure session that follows the TLS handshake. +For SNI to function, the client sends the host name for the secure session to the server during the TLS handshake so the server can provide the correct certificate. The client uses the furnished certificate for encrypted communication with the server during the secure session that follows the TLS handshake. All websites must run on the same Kestrel instance. Kestrel doesn't support sharing an IP address and port across multiple instances without a reverse proxy. SNI can be configured in two ways: -* Configure a mapping between host names and HTTPS options in [Configuration](xref:fundamentals/configuration/index). For example, JSON in the `appsettings.json` file. -* Create an endpoint in code and select a certificate using the host name with the callback. +* Configure a mapping between host names and HTTPS options in [Configuration](xref:fundamentals/configuration/index). For example, specify JSON in the _appsettings.json_ file. +* Create an endpoint in code and select a certificate by using the host name with the callback property. ### Configure SNI in appsettings.json @@ -473,20 +459,20 @@ The following configuration adds an endpoint named `MySniEndpoint` that uses SNI [!INCLUDE [](~/includes/credentials-warning.md)] -HTTPS options that can be overridden by SNI: +SNI can override the following HTTPS options: * `Certificate` configures the [certificate source](#certificate-sources). * `Protocols` configures the allowed [HTTP protocols](xref:Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols). * `SslProtocols` configures the allowed [SSL protocols](xref:System.Security.Authentication.SslProtocols). * `ClientCertificateMode` configures the [client certificate requirements](xref:Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode). -The host name supports wildcard matching: +The host name supports the following wildcard matching: -* Exact match. For example, `a.example.org` matches `a.example.org`. -* Wildcard prefix. If there are multiple wildcard matches, then the longest pattern is chosen. For example, `*.example.org` matches `b.example.org` and `c.example.org`. -* Full wildcard. `*` matches everything else, including clients that aren't using SNI and don't send a host name. +- **Exact match**: For example, `a.example.org` matches `a.example.org`. +- **Wildcard prefix**: If there are multiple wildcard matches, the longest pattern is selected. For example, `*.example.org` matches `b.example.org` and `c.example.org`. +- **Full wildcard**: The wildcard `*` matches everything else, including clients that don't use SNI and don't send a host name. -The matched SNI configuration is applied to the endpoint for the connection, overriding values on the endpoint. If a connection doesn't match a configured SNI host name, then the connection is refused. +The matched SNI configuration is applied to the endpoint for the connection, overriding values on the endpoint. If a connection doesn't match a configured SNI host name, the connection is refused. ### Configure SNI with code @@ -504,47 +490,49 @@ Kestrel supports SNI via the `ServerCertificateSelector` callback. The callback #### SNI with `ServerOptionsSelectionCallback` -Kestrel supports additional dynamic TLS configuration via the `ServerOptionsSelectionCallback` callback. The callback is invoked once per connection to allow the app to inspect the host name and select the appropriate certificate and TLS configuration. Default certificates and `ConfigureHttpsDefaults` aren't used with this callback. +Kestrel supports more dynamic TLS configuration via the `ServerOptionsSelectionCallback` callback. The callback is invoked once per connection to allow the app to inspect the host name and select the appropriate certificate and TLS configuration. Default certificates and `ConfigureHttpsDefaults` aren't used with this callback. :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_ServerOptionsSelectionCallback"::: #### SNI with `TlsHandshakeCallbackOptions` -Kestrel supports additional dynamic TLS configuration via the `TlsHandshakeCallbackOptions.OnConnection` callback. The callback is invoked once per connection to allow the app to inspect the host name and select the appropriate certificate, TLS configuration, and other server options. Default certificates and `ConfigureHttpsDefaults` aren't used with this callback. +Kestrel supports more dynamic TLS configuration via the `TlsHandshakeCallbackOptions.OnConnection` callback. The callback is invoked once per connection to allow the app to inspect the host name and select the appropriate certificate, TLS configuration, and other server options. Default certificates and `ConfigureHttpsDefaults` aren't used with this callback. :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_TlsHandshakeCallbackOptions"::: ## Configure HTTP protocols -Kestrel supports all commonly used HTTP versions. Endpoints can be configured to support different HTTP versions using the enum, which specifies available HTTP version options. +Kestrel supports all commonly used HTTP versions. Endpoints can be configured to support different HTTP versions by using the enum, which specifies available HTTP version options. TLS is required to support more than one HTTP version. The TLS [Application-Layer Protocol Negotiation (ALPN)](https://tools.ietf.org/html/rfc7301#section-3) handshake is used to negotiate the connection protocol between the client and the server when an endpoint supports multiple protocols. -| `HttpProtocols` value | Connection protocol permitted | -|--|--| -| `Http1` | HTTP/1.1 only. Can be used with or without TLS. | -| `Http2` | HTTP/2 only. May be used without TLS only if the client supports a [Prior Knowledge mode](https://tools.ietf.org/html/rfc7540#section-3.4). | -| `Http3` | HTTP/3 only. Requires TLS. The client may need to be configured to use HTTP/3 only. | -| `Http1AndHttp2` | HTTP/1.1 and HTTP/2. HTTP/2 requires the client to select HTTP/2 in the TLS [Application-Layer Protocol Negotiation (ALPN)](https://tools.ietf.org/html/rfc7301#section-3) handshake; otherwise, the connection defaults to HTTP/1.1. | -| `Http1AndHttp2AndHttp3` | HTTP/1.1, HTTP/2 and HTTP/3. The first client request normally uses HTTP/1.1 or HTTP/2, and the [`alt-svc` response header](xref:fundamentals/servers/kestrel/http3#alt-svc) prompts the client to upgrade to HTTP/3. HTTP/2 and HTTP/3 requires TLS; otherwise, the connection defaults to HTTP/1.1. | +| HttpProtocols value | Allowed protocol | Notes | +|---|---|---| +| `Http1` | HTTP/1.1 | Can be used with or without TLS. | +| `Http2` | HTTP/2 | Can be used without TLS, only if the client supports a [Prior Knowledge mode](https://tools.ietf.org/html/rfc7540#section-3.4). | +| `Http3` | HTTP/3 | **Requires TLS**. The client might need to be configured to use HTTP/3 only. | +| `Http1AndHttp2` | HTTP/1.1
HTTP/2 | HTTP/2 requires the client to select HTTP/2 in the TLS [Application-Layer Protocol Negotiation (ALPN)](https://tools.ietf.org/html/rfc7301#section-3) handshake. Otherwise, the connection defaults to HTTP/1.1. | +| `Http1AndHttp2AndHttp3` | HTTP/1.1
HTTP/2
HTTP/3 | The first client request normally uses HTTP/1.1 or HTTP/2. The ['alt-svc' response header](xref:fundamentals/servers/kestrel/http3#alt-svc) prompts the client to upgrade to HTTP/3. HTTP/2 and HTTP/3 requires TLS. Otherwise, the connection defaults to HTTP/1.1. | The default protocol value for an endpoint is `HttpProtocols.Http1AndHttp2`. -TLS restrictions for HTTP/2: +### TLS restrictions for HTTP/2 -* TLS version 1.2 or later -* Renegotiation disabled -* Compression disabled +When you use the HTTP/2 protocol for the connection, the following TLS restrictions apply: + +* Requires TLS version 1.2 or later +* Renegotiation is disabled +* Compression is disabled * Minimum ephemeral key exchange sizes: - * Elliptic curve Diffie-Hellman (ECDHE) [[RFC4492](https://www.ietf.org/rfc/rfc4492.txt)]: 224 bits minimum - * Finite field Diffie-Hellman (DHE) [`TLS12`]: 2048 bits minimum -* Cipher suite not prohibited. + * Elliptic curve Diffie-Hellman (ECDHE) (see [[RFC 4492](https://www.ietf.org/rfc/rfc4492.txt)]): 224 bits minimum + * Finite field Diffie-Hellman (DHE) (see TLS12 in [[RFC 5246](https://www.rfc-editor.org/rfc/rfc5246)]): 2,048 bits minimum +* The Cipher suite isn't prohibited. -`TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` [`TLS-ECDHE`] with the P-256 elliptic curve [`FIPS186`] is supported by default. +The `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` format (see TLS-ECDHE in [[RFC 8422](https://www.rfc-editor.org/rfc/rfc8422)]) with the P-256 elliptic curve (see [[FIPS186](https://csrc.nist.gov/pubs/fips/186-5/final)]) is supported by default. ### Configure HTTP protocols in appsettings.json -The following `appsettings.json` example establishes the HTTP/1.1 connection protocol for a specific endpoint: +The following the _appsettings.json_ file example establishes the HTTP/1.1 connection protocol for a specific endpoint: ```json { @@ -559,7 +547,7 @@ The following `appsettings.json` example establishes the HTTP/1.1 connection pro } ``` -A default protocol can be configured in the `Kestrel:EndpointDefaults` section. The following `appsettings.json` example establishes HTTP/1.1 as the default connection protocol for all endpoints: +A default protocol can be configured in the `Kestrel:EndpointDefaults` section. The following _appsettings.json_ file example establishes HTTP/1.1 as the default connection protocol for all endpoints: ```json { @@ -575,33 +563,27 @@ Protocols specified in code override values set by configuration. ### Configure HTTP protocols in code - is used to specify protocols with the enum. +The is used to specify protocols with the enum. -The following example configures an endpoint for HTTP/1.1, HTTP/2, and HTTP/3 connections on port 8000. Connections are secured by TLS with a supplied certificate: +The following example configures an endpoint for HTTP/1.1, HTTP/2, and HTTP/3 connections on port 8000. Connections are made secure with TLS and a supplied certificate: :::code language="csharp" source="~/fundamentals/servers/kestrel/samples/6.x/KestrelSample/Snippets/Program.cs" id="snippet_ConfigureKestrelProtocols"::: -:::moniker-end - :::moniker range=">= aspnetcore-9.0" ## Customize Kestrel named pipe endpoints Kestrel's named pipe support includes advanced customization options. The [CreateNamedPipeServerStream](/dotnet/api/microsoft.aspnetcore.server.kestrel.transport.namedpipes.namedpipetransportoptions.createnamedpipeserverstream) property on the named pipe options allows pipes to be customized per-endpoint. -This is useful, for example, in a Kestrel app that requires two pipe endpoints with different [access security](/windows/win32/ipc/named-pipe-security-and-access-rights). The `CreateNamedPipeServerStream` option can be used to create pipes with custom security settings, depending on the pipe name. +This approach is useful in a Kestrel app that requires two pipe endpoints with different [access security](/windows/win32/ipc/named-pipe-security-and-access-rights). The `CreateNamedPipeServerStream` option can be used to create pipes with custom security settings, depending on the pipe name. :::code language="csharp" source="~/fundamentals/servers/kestrel/endpoints/samples/KestrelNamedEP/Program.cs" highlight="15-33" id="snippet_1"::: :::moniker-end -:::moniker range=">= aspnetcore-8.0" - -## See also +## Related content -* -* - -:::moniker-end +* [Kestrel web server in ASP.NET Core](xref:fundamentals/servers/kestrel) +* [Configure options for the ASP.NET Core Kestrel web server](xref:fundamentals/servers/kestrel/options) [!INCLUDE [endpoints5-7](~/fundamentals/servers/kestrel/endpoints/includes/endpoints5-7.md)] diff --git a/aspnetcore/includes/credentials-warning.md b/aspnetcore/includes/credentials-warning.md index 584d9ed71c5b..9d8858f77651 100644 --- a/aspnetcore/includes/credentials-warning.md +++ b/aspnetcore/includes/credentials-warning.md @@ -1,2 +1,6 @@ > [!WARNING] -> In the preceding example, the certificate password is stored in plain-text in `appsettings.json`. The `$CREDENTIAL_PLACEHOLDER$` token is used as a placeholder for the certificate's password. To store certificate passwords securely in development environments, see [Protect secrets in development](xref:security/app-secrets). To store certificate passwords securely in production environments, see [Azure Key Vault configuration provider](xref:security/key-vault-configuration). Development secrets shouldn't be used for production or test. +> In the example code, the certificate password is stored as plain text in the _appsettings.json_ file. +> The `$CREDENTIAL_PLACEHOLDER$` token is used as a placeholder for the certificate password. +> To store certificate passwords securely in development environments, see [Protect secrets in development](xref:security/app-secrets). +> To store certificate passwords securely in production environments, see [Azure Key Vault configuration provider](xref:security/key-vault-configuration). +> It's a best practice to not use development secrets for production or testing. diff --git a/aspnetcore/includes/http-ports.md b/aspnetcore/includes/http-ports.md index a4676e55d18a..a27221fd9dba 100644 --- a/aspnetcore/includes/http-ports.md +++ b/aspnetcore/includes/http-ports.md @@ -1,14 +1,14 @@ -Apps and containers are often given only a port to listen on, like port 80, without additional constraints like host or path. HTTP_PORTS and HTTPS_PORTS are config keys that specify the listening ports for the Kestrel and HTTP.sys servers. These keys may be specified as environment variables defined with the `DOTNET_` or `ASPNETCORE_` prefixes, or specified directly through any other config input, such as `appsettings.json`. Each is a semicolon-delimited list of port values, as shown in the following example: +Most configurations for apps and containers define only a port for listening, like port 80, without specifying other constraints like the host or path. HTTP_PORTS and HTTPS_PORTS are config keys that specify the listening ports for the Kestrel and HTTP.sys servers. You can specify the keys as environment variables defined with the `DOTNET_` or `ASPNETCORE_` prefixes, or set them directly through any other config input, such as the _appsettings.json_ file. Each configuration is a semicolon-delimited list of port values, as shown in the following example: -``` +```json ASPNETCORE_HTTP_PORTS=80;8080 ASPNETCORE_HTTPS_PORTS=443;8081 ``` -The preceding example is shorthand for the following configuration, which specifies the scheme (HTTP or HTTPS) and any host or IP. +The configuration in the example is shorthand for the following specification, which defines the scheme (HTTP or HTTPS) and any host or IP: -``` +```json ASPNETCORE_URLS=http://*:80/;http://*:8080/;https://*:443/;https://*:8081/ ``` -The HTTP_PORTS and HTTPS_PORTS configuration keys are lower priority and are overridden by URLS or values provided directly in code. Certificates still need to be configured separately via server-specific mechanics for HTTPS. +The HTTP_PORTS and HTTPS_PORTS configuration keys are lower priority. If other URLs or values are set directly in code, they can override the configuration keys. You still need to configure certificates separately by using server-specific mechanics for HTTPS. diff --git a/aspnetcore/includes/make-x509-cert.md b/aspnetcore/includes/make-x509-cert.md index 8e3def3e5ae4..3f32f9f1fb61 100644 --- a/aspnetcore/includes/make-x509-cert.md +++ b/aspnetcore/includes/make-x509-cert.md @@ -1,3 +1,3 @@ -On Windows, self-signed certificates can be created using the [`New-SelfSignedCertificate` PowerShell cmdlet](/powershell/module/pki/new-selfsignedcertificate). For an unsupported example, see [`UpdateIISExpressSSLForChrome.ps1`](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/includes/make-x509-cert/UpdateIISExpressSSLForChrome.ps1). +On Windows, self-signed certificates can be created by using the [New-SelfSignedCertificate PowerShell cmdlet](/powershell/module/pki/new-selfsignedcertificate). For an unsupported example, see the [UpdateIISExpressSSLForChrome.ps1](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/includes/make-x509-cert/UpdateIISExpressSSLForChrome.ps1) certificate file on GitHub. -On macOS, Linux, and Windows, certificates can be created using [OpenSSL](https://www.openssl.org/). +On macOS, Linux, and Windows, create certificates can be created by using [OpenSSL](https://www.openssl.org/).