diff --git a/.github/workflows/quest.yml b/.github/workflows/quest.yml index ce5d13549beb..af869c31b542 100644 --- a/.github/workflows/quest.yml +++ b/.github/workflows/quest.yml @@ -46,7 +46,7 @@ jobs: uses: dotnet/docs-tools/actions/sequester@main env: ImportOptions__ApiKeys__GitHubToken: ${{ secrets.GITHUB_TOKEN }} - ImportOptions__ApiKeys__AzureAccessToken: ${{ steps.azure-oidc-auth.outputs.access-token }}s + ImportOptions__ApiKeys__AzureAccessToken: ${{ steps.azure-oidc-auth.outputs.access-token }} ImportOptions__ApiKeys__QuestKey: ${{ secrets.QUEST_KEY }} ImportOptions__ApiKeys__SequesterPrivateKey: ${{ secrets.SEQUESTER_PRIVATEKEY }} ImportOptions__ApiKeys__SequesterAppID: ${{ secrets.SEQUESTER_APPID }} diff --git a/aspnetcore/blazor/security/_static/entra-external-id-logout-exception.png b/aspnetcore/blazor/security/_static/entra-external-id-logout-exception.png new file mode 100644 index 000000000000..3bd8a8b37d1b Binary files /dev/null and b/aspnetcore/blazor/security/_static/entra-external-id-logout-exception.png differ diff --git a/aspnetcore/blazor/security/includes/troubleshoot-server.md b/aspnetcore/blazor/security/includes/troubleshoot-server.md index 756fd0546453..d7ecef25fc7f 100644 --- a/aspnetcore/blazor/security/includes/troubleshoot-server.md +++ b/aspnetcore/blazor/security/includes/troubleshoot-server.md @@ -6,6 +6,16 @@ To enable debug or trace logging for Blazor WebAssembly authentication, see the ### Common errors +* Debugger breaks on an exception during logout with Microsoft Entra External ID + + The following exception stops the Visual Studio debugger during logout with [Microsoft Entra External ID](/entra/external-id/external-identities-overview): + + > :::no-loc text="Uncaught TypeError TypeError: Failed to execute 'postMessage' on 'Window': The provided value cannot be converted to a sequence."::: + + ![Visual Studio Debugger breaking on JavaScript exception during logout](../_static/entra-external-id-logout-exception.png) + + The exception is thrown from Entra JavaScript code, so this isn't a problem with ASP.NET Core. The exception doesn't impact app functionality in production, so the exception can be ignored during local development testing. + * Misconfiguration of the app or Identity Provider (IP) The most common errors are caused by incorrect configuration. The following are a few examples: diff --git a/aspnetcore/fundamentals/servers/yarp/config-providers.md b/aspnetcore/fundamentals/servers/yarp/config-providers.md index 790d2649a469..e92e47a8962f 100644 --- a/aspnetcore/fundamentals/servers/yarp/config-providers.md +++ b/aspnetcore/fundamentals/servers/yarp/config-providers.md @@ -68,10 +68,10 @@ The configuration objects and collections supplied to the proxy should be read-o If the `IChangeToken` supports `ActiveChangeCallbacks`, once the proxy has processed the initial set of configurations it will register a callback with this token. If the provider does not support callbacks then `HasChanged` will be polled every 5 minutes. When the provider wants to provide a new configuration to the proxy it should: -- load that configuration in the background. +- Load that configuration in the background. - Route and cluster objects are immutable, so new instances have to be created for any new data. - Objects for unchanged routes and clusters can be re-used, or new instances can be created - changes will be detected by diffing them. -- optionally validate the configuration using the [IConfigValidator](xref:Yarp.ReverseProxy.Configuration.IConfigValidator), and only then signal the `IChangeToken` from the prior `IProxyConfig` instance that new data is available. The proxy will call `GetConfig()` again to retrieve the new data. +- Optionally validate the configuration using the [IConfigValidator](xref:Yarp.ReverseProxy.Configuration.IConfigValidator), and only then signal the `IChangeToken` from the prior `IProxyConfig` instance that new data is available. The proxy will call `GetConfig()` again to retrieve the new data. There are important differences when reloading configuration vs the first configuration load. - The new configuration will be diffed against the current one and only modified routes or clusters will be updated. The update will be applied atomically and will only affect new requests, not requests currently in progress. diff --git a/aspnetcore/fundamentals/servers/yarp/dests-health-checks.md b/aspnetcore/fundamentals/servers/yarp/dests-health-checks.md index 58671a6d5b7c..4dadeb696d00 100644 --- a/aspnetcore/fundamentals/servers/yarp/dests-health-checks.md +++ b/aspnetcore/fundamentals/servers/yarp/dests-health-checks.md @@ -84,12 +84,12 @@ Active health check settings can also be defined in code via the corresponding t `Cluster/HealthCheck/Active` section and [ActiveHealthCheckConfig](xref:Yarp.ReverseProxy.Configuration.ActiveHealthCheckConfig): -- `Enabled` - flag indicating whether active health check is enabled for a cluster. Default `false` -- `Interval` - period of sending health probing requests. Default `00:00:15` -- `Timeout` - probing request timeout. Default `00:00:10` -- `Policy` - name of a policy evaluating destinations' active health states. Mandatory parameter -- `Path` - health check path on all cluster's destinations. Default `null`. -- `Query` - health check query on all cluster's destinations. Default `null`. +- `Enabled`: Flag indicating whether active health check is enabled for a cluster. Default `false` +- `Interval`: Period of sending health probing requests. Default `00:00:15` +- `Timeout`: Probing request timeout. Default `00:00:10` +- `Policy`: Name of a policy evaluating destinations' active health states. Mandatory parameter +- `Path`: Health check path on all cluster's destinations. Default `null`. +- `Query`: Health check query on all cluster's destinations. Default `null`. `Destination` section and [DestinationConfig](xref:Yarp.ReverseProxy.Configuration.DestinationConfig). @@ -346,10 +346,10 @@ public class FirstUnsuccessfulResponseHealthPolicy : IPassiveHealthCheckPolicy ## Available destination collection Destinations health state is used to determine which of them are eligible for receiving proxied requests. Each cluster maintains its own list of available destinations on `AvailableDestinations` property of the [ClusterDestinationState](xref:Yarp.ReverseProxy.Model.ClusterDestinationsState) type. That list gets rebuilt when any destination's health state changes. The [IClusterDestinationsUpdater](xref:Yarp.ReverseProxy.Health.IClusterDestinationsUpdater) controls that process and calls an [IAvailableDestinationsPolicy](xref:Yarp.ReverseProxy.Health.IAvailableDestinationsPolicy) configured on the cluster to actually choose the available destinations from the all cluster's destinations. There are the following built-in policies provided and custom ones can be implemented if necessary. -- `HealthyAndUnknown` - inspects each `DestinationState` and adds it on the available destination list if all of the following statements are TRUE. If no destinations are available then requests will get a 503 error. +- `HealthyAndUnknown` - Inspects each `DestinationState` and adds it on the available destination list if all of the following statements are TRUE. If no destinations are available then requests will get a 503 error. - Active health checks are disabled on the cluster OR `DestinationHealthState.Active != DestinationHealth.Unhealthy` - Passive health checks are disabled on the cluster OR `DestinationHealthState.Passive != DestinationHealth.Unhealthy` -- `HealthyOrPanic` - calls `HealthyAndUnknown` policy at first to get the available destinations. If none of them are returned from this call, it marks all cluster's destinations as available. This is the default policy. +- `HealthyOrPanic` - Calls `HealthyAndUnknown` policy at first to get the available destinations. If none of them are returned from this call, it marks all cluster's destinations as available. This is the default policy. **NOTE**: An available destination policy configured on a cluster will be always called regardless of if any health check is enabled on the given cluster. The health state of a disabled health check is set to `Unknown`. diff --git a/aspnetcore/fundamentals/servers/yarp/diagnosing-yarp-issues.md b/aspnetcore/fundamentals/servers/yarp/diagnosing-yarp-issues.md index 8cf7b43ca0ee..d99b720cc0b8 100644 --- a/aspnetcore/fundamentals/servers/yarp/diagnosing-yarp-issues.md +++ b/aspnetcore/fundamentals/servers/yarp/diagnosing-yarp-issues.md @@ -9,17 +9,17 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- - # YARP Diagnosing YARP-based proxies When using a reverse proxy, there is an additional hop from the client to the proxy, and then from the proxy to destination for things to go wrong. This topic should provide some hints and tips for how to debug and diagnose issues when they occur. It assumes that the proxy is already running, and so does not include problems at startup such as configuration errors. ## Logging + The first step to being able to tell what is going on with YARP is to turn on [logging](/aspnet/core/fundamentals/logging/#configure-logging). This is a configuration flag so can be changed on the fly. YARP is implemented as a middleware component for ASP.NET Core, so you need to enable logging for both YARP and ASP.NET to get the complete picture of what is going on. By default ASP.NET will log to the console, and the configuration file can be used to control the level of logging. -```Json +```json //Sets the Logging level for ASP.NET "Logging": { "LogLevel": { @@ -32,40 +32,41 @@ By default ASP.NET will log to the console, and the configuration file can be us }, ``` -You want logging infomation from the "Microsoft.AspNetCore.\*" and "Yarp.ReverseProxy.\*" providers. The example above will emit "Information" level events from both providers to the Console. Changing the level to "Debug" will show additional entries. ASP.NET implements change detection for configuration files, so you can edit the appsettings.json file (or appsettings.development.json if running from Visual Studio) while the project is running and observe changes to the log output. +You want logging information from the `Microsoft.AspNetCore.\*` and `Yarp.ReverseProxy.\*` providers. The preceding example emits `Information`-level events from both providers to the console. Changing the level to `Debug` shows additional entries. ASP.NET implements change detection for configuration files, so you can edit the `appsettings.json` file (or `appsettings.development.json` for the `Development` environment) while the project is running and observe changes to the log output. -> Note: Settings in the appsettings.development.json file will override settings in appsettings.json when running in development, so make sure that if you are editing appsettings.json that the values are not overridden. +> [!NOTE] +> Settings in the `appsettings.development.json` file override settings in `appsettings.json` when running in the `Development` environment, so make sure that if you are editing `appsettings.json` that the values aren't overridden. -### Understanding Log entries +### Understanding log entries The logging output is directly tied to the way that ASP.NET Core processes requests. It's important to realize that as middleware, YARP is relying on much of the ASP.NET functionality to process the requests, for example the following is for the processing of a request with "Debug" mode enabled: | Level | Log Message | Description | -| ----- | ----------- | ----------- | +| --- | --- | --- | | dbug | Microsoft.AspNetCore.Server.Kestrel.Connections[39]
Connection id "0HMCD0JK7K51U" accepted.| Connections are independent of requests, so this is a new connection | | dbug | Microsoft.AspNetCore.Server.Kestrel.Connections[1]
Connection id "0HMCD0JK7K51U" started. | | -| info | Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET http://localhost:5000/ - - | This is the incomming request to ASP.NET | -| dbug | Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[0]
Wildcard detected, all requests with hosts will be allowed. | My configuation does not tie endpoints to specific hostnames | +| info | Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET http://localhost:5000/ - - | This is the incoming request to ASP.NET | +| dbug | Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[0]
Wildcard detected, all requests with hosts will be allowed. | My configuration does not tie endpoints to specific hostnames | | dbug | Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001]
1 candidate(s) found for the request path '/' | This shows what possible matches there are for the route | -| dbug | Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005]
Endpoint 'minimumroute' with route pattern '{\*\*catch-all}' is valid for the request path '/' | The mimimum route from YARPs configuration has matched| -| dbug | Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1]
Request matched endpoint 'minimumroute' | | -| info | Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'minimumroute' | | -| info | Yarp.ReverseProxy.Forwarder.HttpForwarder[9]
Proxying to http://www.example.com/ | YARP is proxying the request to example.com | -| info | Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'minimumroute' | | -| dbug | Microsoft.AspNetCore.Server.Kestrel.Connections[9]
Connection id "0HMCD0JK7K51U" completed keep alive response. | The response has finished, but connection can be kept alive. | +| dbug | Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005]
Endpoint 'minimumroute' with route pattern '{\*\*catch-all}' is valid for the request path '/' | The minimum route from YARPs configuration has matched| +| dbug | Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1]
Request matched endpoint 'minimumroute' | | +| info | Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'minimumroute' | | +| info | Yarp.ReverseProxy.Forwarder.HttpForwarder[9]
Proxying to http://www.example.com/ | YARP is proxying the request to example.com | +| info | Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'minimumroute' | | +| dbug | Microsoft.AspNetCore.Server.Kestrel.Connections[9]
Connection id "0HMCD0JK7K51U" completed keep alive response. | The response has finished, but connection can be kept alive. | | info | Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 GET http://localhost:5000/ - - - 200 1256 text/html;+charset=utf-8 12.7797ms| The response completed with status code 200, responding with 1256 bytes as text/html in ~13ms. | -| dbug | Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6]
Connection id "0HMCD0JK7K51U" received FIN. | Diagnostic information about the connection to determine who closed it and how cleanly | -| dbug | Microsoft.AspNetCore.Server.Kestrel.Connections[10]
Connection id "0HMCD0JK7K51U" disconnecting. | | -| dbug | Microsoft.AspNetCore.Server.Kestrel.Connections[2]
Connection id "0HMCD0JK7K51U" stopped. | | -| dbug | Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
Connection id "0HMCD0JK7K51U" sending FIN because: "The Socket transport's send loop completed gracefully." | | +| dbug | Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6]
Connection id "0HMCD0JK7K51U" received FIN. | Diagnostic information about the connection to determine who closed it and how cleanly | +| dbug | Microsoft.AspNetCore.Server.Kestrel.Connections[10]
Connection id "0HMCD0JK7K51U" disconnecting. | | +| dbug | Microsoft.AspNetCore.Server.Kestrel.Connections[2]
Connection id "0HMCD0JK7K51U" stopped. | | +| dbug | Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
Connection id "0HMCD0JK7K51U" sending FIN because: "The Socket transport's send loop completed gracefully." | | The above gives general information about the request and how it was processed. -### Using ASP.NET Request Logging +### Using ASP.NET request logging -ASP.NET includes a middleware component that can be used to provide more details about the request and response. The `UseHttpLogging` component can be added to the request pipeline. It will add additional entries to the log detailing the incoming and outgoing request headers. +ASP.NET includes a middleware component that can be used to provide more details about the request and response. The `UseHttpLogging` component can be added to the request pipeline, which adds additional entries to the log detailing the incoming and outgoing request headers. -``` C# +```csharp app.UseHttpLogging(); // Enable endpoint routing, required for the reverse proxy app.UseRouting(); @@ -75,7 +76,7 @@ app.MapReverseProxy(); For example: -```Console +```console info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1] Request: Protocol: HTTP/1.1 @@ -102,7 +103,7 @@ info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2] X-Cache: [Redacted] ``` -## Using Telemetry Events +## Using telemetry events We recommend reading [Networking telemetry in .NET](/dotnet/fundamentals/networking/telemetry/overview) as a primer on how to consume networking telemetry in .NET. @@ -111,7 +112,7 @@ The [Metrics sample](https://github.com/microsoft/reverse-proxy/tree/main/sample * `ForwarderTelemetryConsumer` * `HttpClientTelemetryConsumer` -To use either of these you create a class implementing a `[telemetry interface](https://microsoft.github.io/reverse-proxy/api/Yarp.Telemetry.Consumption.html#interfaces)`, such as [`IForwarderTelemetryConsumer`](https://github.com/microsoft/reverse-proxy/blob/release/latest/src/TelemetryConsumption/Forwarder/IForwarderTelemetryConsumer.cs): +To use either of these, create a class implementing a [`Yarp.Telemetry.Consumption` interface](xref:Yarp.Telemetry.Consumption#interfaces), such as : ```C# public class ForwarderTelemetry : IForwarderTelemetryConsumer @@ -119,50 +120,62 @@ public class ForwarderTelemetry : IForwarderTelemetryConsumer /// Called before forwarding a request. public void OnForwarderStart(DateTime timestamp, string destinationPrefix) { - Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => OnForwarderStart :: Destination prefix: {destinationPrefix}"); + Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => " + + $"OnForwarderStart :: Destination prefix: {destinationPrefix}"); } /// Called after forwarding a request. public void OnForwarderStop(DateTime timestamp, int statusCode) { - Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => OnForwarderStop :: Status: {statusCode}"); + Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => " + + $"OnForwarderStop :: Status: {statusCode}"); } /// Called before if forwarding the request failed. public void OnForwarderFailed(DateTime timestamp, ForwarderError error) { - Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => OnForwarderFailed :: Error: {error.ToString()}"); + Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => " + + $"OnForwarderFailed :: Error: {error.ToString()}"); } /// Called when reaching a given stage of forwarding a request. public void OnForwarderStage(DateTime timestamp, ForwarderStage stage) { - Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => OnForwarderStage :: Stage: {stage.ToString()}"); + Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => " + + $"OnForwarderStage :: Stage: {stage.ToString()}"); } /// Called periodically while a content transfer is active. - public void OnContentTransferring(DateTime timestamp, bool isRequest, long contentLength, long iops, TimeSpan readTime, TimeSpan writeTime) + public void OnContentTransferring(DateTime timestamp, bool isRequest, long contentLength, + long iops, TimeSpan readTime, TimeSpan writeTime) { - Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => OnContentTransferring :: Is request: {isRequest}, Content length: {contentLength}, IOps: {iops}, Read time: {readTime:s\\.fff}, Write time: {writeTime:s\\.fff}"); + Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => " + + $"OnContentTransferring :: Is request: {isRequest}, Content length: {contentLength}, " + + $"IOps: {iops}, Read time: {readTime:s\\.fff}, Write time: {writeTime:s\\.fff}"); } /// Called after transferring the request or response content. - public void OnContentTransferred(DateTime timestamp, bool isRequest, long contentLength, long iops, TimeSpan readTime, TimeSpan writeTime, TimeSpan firstReadTime) + public void OnContentTransferred(DateTime timestamp, bool isRequest, long contentLength, + long iops, TimeSpan readTime, TimeSpan writeTime, TimeSpan firstReadTime) { - Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => OnContentTransferred :: Is request: {isRequest}, Content length: {contentLength}, IOps: {iops}, Read time: {readTime:s\\.fff}, Write time: {writeTime:s\\.fff}"); + Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => " + + $"OnContentTransferred :: Is request: {isRequest}, Content length: {contentLength}, " + + $"IOps: {iops}, Read time: {readTime:s\\.fff}, Write time: {writeTime:s\\.fff}"); } /// Called before forwarding a request from `ForwarderMiddleware`, therefore is not called for direct forwarding scenarios. - public void OnForwarderInvoke(DateTime timestamp, string clusterId, string routeId, string destinationId) + public void OnForwarderInvoke(DateTime timestamp, string clusterId, string routeId, + string destinationId) { - Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => OnForwarderInvoke:: Cluster id: {clusterId}, Route Id: { routeId}, Destination: {destinationId}"); + Console.WriteLine($"Forwarder Telemetry [{timestamp:HH:mm:ss.fff}] => " + + $"OnForwarderInvoke:: Cluster id: {clusterId}, Route Id: {routeId}, Destination: {destinationId}"); } } ``` -And then register the class as part of services, for example: +Tegister the class as part of services, for example: -```C# +```csharp services.AddTelemetryConsumer(); // Add the reverse proxy to capability to the server @@ -171,24 +184,28 @@ var proxyBuilder = services.AddReverseProxy(); proxyBuilder.LoadFromConfig(Configuration.GetSection("ReverseProxy")); ``` -Then you will log details on each part of the request, for example: +Details are logged on each part of the request, for example: -```Console -Forwarder Telemetry [06:40:48.186] => OnForwarderInvoke:: Cluster id: minimumcluster, Route Id: minimumroute, Destination: example.com -Forwarder Telemetry [06:41:00.269] => OnForwarderStart :: Destination prefix: http://www.example.com/ +```console +Forwarder Telemetry [06:40:48.186] => OnForwarderInvoke:: + Cluster id: minimumcluster, Route Id: minimumroute, Destination: example.com +Forwarder Telemetry [06:41:00.269] => OnForwarderStart :: + Destination prefix: http://www.example.com/ Forwarder Telemetry [06:41:00.298] => OnForwarderStage :: Stage: SendAsyncStart Forwarder Telemetry [06:41:00.507] => OnForwarderStage :: Stage: SendAsyncStop -Forwarder Telemetry [06:41:00.530] => OnForwarderStage :: Stage: ResponseContentTransferStart +Forwarder Telemetry [06:41:00.530] => OnForwarderStage :: Stage: + ResponseContentTransferStart Forwarder Telemetry [06:41:03.655] => OnForwarderStop :: Status: 200 ``` -The events for Telemetry are fired as they occur, so you can [fish out the HttpContext](/aspnet/core/fundamentals/http-context#use-httpcontext-from-custom-components) and the YARP feature from it: +The events for telemetry are fired as they occur, so you can [obtain the `HttpContext`](/aspnet/core/fundamentals/http-context#use-httpcontext-from-custom-components) and the YARP feature from it: -``` C# +```csharp services.AddTelemetryConsumer(); services.AddHttpContextAccessor(); ... -public void OnForwarderInvoke(DateTime timestamp, string clusterId, string routeId, string destinationId) +public void OnForwarderInvoke(DateTime timestamp, string clusterId, string routeId, + string destinationId) { var context = new HttpContextAccessor().HttpContext; var YarpFeature = context.GetReverseProxyFeature(); @@ -204,7 +221,7 @@ public void OnForwarderInvoke(DateTime timestamp, string clusterId, string route Another way to inspect the state for requests is to insert additional middleware into the request pipeline. You can insert between the other stages to see the state of the request. -```C# +```csharp // We can customize the proxy pipeline and add/remove/replace steps app.MapReverseProxy(proxyPipeline => { @@ -234,18 +251,19 @@ public Task MyCustomProxyStep(HttpContext context, Func next) You can also use [ASP.NET middleware](/aspnet/core/fundamentals/middleware/write) within Configure that will enable you to inspect the request before the proxy pipeline. -> **Note:** The proxy will stream the response from the destination server back to the client, so the response headers and body are not readily accessible via middleware. +> [!NOTE] +> The proxy streams the response from the destination server back to the client, so the response headers and body aren't readily accessible via middleware. ## Using the debugger -A debugger, such as Visual Studio can be attached to the proxy process. However, unless you have existing middleware, there is not a good place in the app code to break and inspect the state of the request. Therefore the debugger is best used in conjunction with one of the techniques above so that you have distinct places to insert breakpoints etc. +A debugger, such as Visual Studio, can be attached to the proxy process. However, unless you have existing middleware, there isn't a good place in the app code to break and inspect the state of the request. Therefore, the debugger is best used in conjunction with one of the preceding techniques so that you have distinct places to insert breakpoints. + +## Network tracing -## Network Tracing +It can be attractive to use network tracing tools like [Fiddler](https://www.telerik.com/fiddler) or [Wireshark](https://www.wireshark.org/) to try to monitor what's happening either side of the proxy. However, be cautious using both tools: -It can be attractive to use network tracing tools like [Fiddler](https://www.telerik.com/fiddler) or [Wireshark](https://www.wireshark.org/) to try to monitor what is happening either side of the proxy. However there are some gotchas to using both tools. +* Fiddler registers itself as a proxy and relies on apps using the default proxy to be able to monitor traffic. This works for inbound traffic from a browser to YARP but won't capture the outbound requests, as YARP is configured to not use the proxy settings for outbound traffic. +* On Windows, Wireshark uses Npcap to capture packet data for network traffic, so it captures both inbound and outbound traffic and can be used to monitor HTTP traffic. +* HTTPS traffic is encrypted and isn't automatically decryptable by network monitoring tools. Each tool has workarounds that may enable traffic to be monitored, but they require risky use of certificates and changes to trust relationships. Because YARP is making outbound requests, techniques for tricking browsers don't apply to the YARP process. -- Fiddler registers itself as a proxy and relies on applications using the default proxy to be able to monitor traffic. This works for inbound traffic from a browser to YARP, but will not capture the outbound requests as YARP is configured to not use the proxy settings for outbound traffic. -- On windows Wireshark uses Npcap to capture packet data for network traffic, so it will capture both inbound and outbound traffic, and can be used to monitor HTTP traffic. Wireshark works out of the box for HTTP traffic. -- HTTPS traffic is encrypted, and so is not automatically decryptable by network monitoring tools. Each tool has workarounds that may enable traffic to be monitored, but they require hacking around with certificates and trust relationships. Because YARP is making outbound requests, techniques for tricking browsers do not apply to the YARP process. - -The protocol choice for outbound traffic is made based on the destination URL in the cluster configuration. If traffic monitoring is being used for diagnostics then, if possible, changing the outbound URLs to "http://" may be simplest approach to enable the monitoring tools to work, provided the issues being diagnosed are not transport protocol related. +The protocol choice for outbound traffic is made based on the destination URL in the cluster configuration. If traffic monitoring is used for diagnostics, changing the outbound URLs to `http://`, if possible, may be the simplest approach to enable the monitoring tools to work, provided the issues being diagnosed aren't transport protocol related. diff --git a/aspnetcore/fundamentals/servers/yarp/extensibility-transforms.md b/aspnetcore/fundamentals/servers/yarp/extensibility-transforms.md index 7b4404510865..465942ec7520 100644 --- a/aspnetcore/fundamentals/servers/yarp/extensibility-transforms.md +++ b/aspnetcore/fundamentals/servers/yarp/extensibility-transforms.md @@ -9,43 +9,42 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- - # Request and Response Transform Extensibility ## Introduction When proxying a request it's common to modify parts of the request or response to adapt to the destination server's requirements or to flow additional data such as the client's original IP address. This process is implemented via Transforms. Types of transforms are defined globally for the application and then individual routes supply the parameters to enable and configure those transforms. The original request objects are not modified by these transforms, only the proxy requests. -YARP includes a set of built-in request and response transforms that can be used. See [Transforms](./transforms.md) for more details. If those transforms are not sufficient, then custom transfrorms can be added. +YARP includes a set of built-in request and response transforms that can be used. See [Transforms](./transforms.md) for more details. If those transforms are not sufficient, then custom transforms can be added. -## RequestTransform +## `RequestTransform` -All request transforms must derive from the abstract base class [RequestTransform](xref:fundamentals/servers/yarp/transforms). These can freely modify the proxy `HttpRequestMessage`. Avoid reading or modifying the request body as this may disrupt the proxying flow. Consider also adding a parametrized extension method on `TransformBuilderContext` for discoverability and easy of use. +All request transforms must derive from the abstract base class [`RequestTransform`](xref:fundamentals/servers/yarp/transforms). These can freely modify the proxy `HttpRequestMessage`. Avoid reading or modifying the request body as this may disrupt the proxying flow. Consider also adding a parametrized extension method on `TransformBuilderContext` for discoverability and ease of use. A request transform may conditionally produce an immediate response such as for error conditions. This prevents any remaining transforms from running and the request from being proxied. This is indicated by setting the `HttpResponse.StatusCode` to a value other than 200, or calling `HttpResponse.StartAsync()`, or writing to the `HttpResponse.Body` or `BodyWriter`. -### AddRequestTransform +### `AddRequestTransform` [AddRequestTransform](xref:Yarp.ReverseProxy.Transforms.TransformBuilderContextFuncExtensions.AddRequestTransform*) is a `TransformBuilderContext` extension method that defines a request transform as a `Func`. This allows creating a custom request transform without implementing a `RequestTransform` derived class. -## ResponseTransform +## `ResponseTransform` -All response transforms must derive from the abstract base class [ResponseTransform](xref:Yarp.ReverseProxy.Transforms.ResponseTransform). These can freely modify the client `HttpResponse`. Avoid reading or modifying the response body as this may disrupt the proxying flow. Consider also adding a parametrized extension method on `TransformBuilderContext` for discoverability and easy of use. +All response transforms must derive from the abstract base class [`ResponseTransform`](xref:Yarp.ReverseProxy.Transforms.ResponseTransform). These can freely modify the client `HttpResponse`. Avoid reading or modifying the response body as this may disrupt the proxying flow. Consider also adding a parametrized extension method on `TransformBuilderContext` for discoverability and easy of use. -### AddResponseTransform +### `AddResponseTransform` [AddResponseTransform](xref:Yarp.ReverseProxy.Transforms.TransformBuilderContextFuncExtensions.AddResponseTransform*) is a `TransformBuilderContext` extension method that defines a response transform as a `Func`. This allows creating a custom response transform without implementing a `ResponseTransform` derived class. -## ResponseTrailersTransform +## `ResponseTrailersTransform` All response trailers transforms must derive from the abstract base class [ResponseTrailersTransform](xref:Yarp.ReverseProxy.Transforms.ResponseTrailersTransform). These can freely modify the client HttpResponse trailers. These run after the response body and should not attempt to modify the response headers or body. Consider also adding a parametrized extension method on `TransformBuilderContext` for discoverability and easy of use. -### AddResponseTrailersTransform +### `AddResponseTrailersTransform` [AddResponseTrailersTransform](xref:Yarp.ReverseProxy.Transforms.TransformBuilderContextFuncExtensions.AddResponseTrailersTransform*) is a `TransformBuilderContext` extension method that defines a response trailers transform as a `Func`. This allows creating a custom response trailers transform without implementing a `ResponseTrailersTransform` derived class. ## Request body transforms -YARP does not provide any built in transforms for modifying the request body. However, the body can be modified in custom transforms. +YARP does not provide any built in transforms for modifying the request body. However, the body can be modified by custom transforms. Be careful about which kinds of requests are modified, how much data gets buffered, enforcing timeouts, parsing untrusted input, and updating the body-related headers like `Content-Length`. @@ -53,22 +52,25 @@ The below example uses simple, inefficient buffering to transform requests. A mo This sample requires YARP 1.1, see https://github.com/microsoft/reverse-proxy/pull/1569. -```C# +```csharp .AddTransforms(context => { context.AddRequestTransform(async requestContext => { - using var reader = new StreamReader(requestContext.HttpContext.Request.Body); + using var reader = + new StreamReader(requestContext.HttpContext.Request.Body); // TODO: size limits, timeouts var body = await reader.ReadToEndAsync(); if (!string.IsNullOrEmpty(body)) { body = body.Replace("Alpha", "Charlie"); var bytes = Encoding.UTF8.GetBytes(body); - // Change Content-Length to match the modified body, or remove it. + // Change Content-Length to match the modified body, or remove it requestContext.HttpContext.Request.Body = new MemoryStream(bytes); - // Request headers are copied before transforms are invoked, update any needed headers on the ProxyRequest - requestContext.ProxyRequest.Content.Headers.ContentLength = bytes.Length; + // Request headers are copied before transforms are invoked, update any + // needed headers on the ProxyRequest + requestContext.ProxyRequest.Content.Headers.ContentLength = + bytes.Length; } }); }); @@ -76,18 +78,19 @@ This sample requires YARP 1.1, see https://github.com/microsoft/reverse-proxy/pu ## Response body transforms -YARP does not provide any built in transforms for modifying the response body. However, the body can be modified in custom transforms. +YARP does not provide any built in transforms for modifying the response body. However, the body can be modified by custom transforms. Be careful about which kinds of responses are modified, how much data gets buffered, enforcing timeouts, parsing untrusted input, and updating the body-related headers like `Content-Length`. You may need to decompress content before modifying it, as indicated by the Content-Encoding header, and afterwards re-compress it or remove the header. The below example uses simple, inefficient buffering to transform responses. A more efficient implementation would wrap the stream returned by `ReadAsStreamAsync()` with a stream that performed the needed modifications as data was proxied from client to server. That would also require removing the Content-Length header since the final length would not be known in advance. -```C# +```csharp .AddTransforms(context => { context.AddResponseTransform(async responseContext => { - var stream = await responseContext.ProxyResponse.Content.ReadAsStreamAsync(); + var stream = + await responseContext.ProxyResponse.Content.ReadAsStreamAsync(); using var reader = new StreamReader(stream); // TODO: size limits, timeouts var body = await reader.ReadToEndAsync(); @@ -98,51 +101,59 @@ The below example uses simple, inefficient buffering to transform responses. A m body = body.Replace("Bravo", "Charlie"); var bytes = Encoding.UTF8.GetBytes(body); - // Change Content-Length to match the modified body, or remove it. + // Change Content-Length to match the modified body, or remove it responseContext.HttpContext.Response.ContentLength = bytes.Length; - // Response headers are copied before transforms are invoked, update any needed headers on the HttpContext.Response. + // Response headers are copied before transforms are invoked, update + // any needed headers on the HttpContext.Response await responseContext.HttpContext.Response.Body.WriteAsync(bytes); } }); }); ``` -## ITransformProvider +## `ITransformProvider` -[ITransformProvider](xref:Yarp.ReverseProxy.Transforms.Builder.ITransformProvider) provides the functionality of `AddTransforms` described above as well as DI integration and validation support. + provides the functionality of `AddTransforms` described above as well as DI integration and validation support. -`ITransformProvider`'s can be registered in DI by calling [AddTransforms<T>()](xref:Microsoft.Extensions.DependencyInjection.ReverseProxyServiceCollectionExtensions). Multiple `ITransformProvider` implementations can be registered and all will be run. +`ITransformProvider`'s can be registered in DI by calling . Multiple `ITransformProvider` implementations can be registered and all will be run. `ITransformProvider` has two methods, `Validate` and `Apply`. `Validate` gives you the opportunity to inspect the route for any parameters that are needed to configure a transform, such as custom metadata, and to return validation errors on the context if any needed values are missing or invalid. The `Apply` method provides the same functionality as AddTransform as discussed above, adding and configuring transforms per route. -```C# +```csharp services.AddReverseProxy() .LoadFromConfig(_configuration.GetSection("ReverseProxy")) .AddTransforms(); ``` -```C# + +```csharp internal class MyTransformProvider : ITransformProvider { public void ValidateRoute(TransformRouteValidationContext context) { - // Check all routes for a custom property and validate the associated transform data. - if (context.Route.Metadata?.TryGetValue("CustomMetadata", out var value) ?? false) + // Check all routes for a custom property and validate the associated + // transform data + if (context.Route.Metadata?.TryGetValue("CustomMetadata", out var value) ?? + false) { if (string.IsNullOrEmpty(value)) { - context.Errors.Add(new ArgumentException("A non-empty CustomMetadata value is required")); + context.Errors.Add(new ArgumentException( + "A non-empty CustomMetadata value is required")); } } } public void ValidateCluster(TransformClusterValidationContext context) { - // Check all clusters for a custom property and validate the associated transform data. - if (context.Cluster.Metadata?.TryGetValue("CustomMetadata", out var value) ?? false) + // Check all clusters for a custom property and validate the associated + // transform data. + if (context.Cluster.Metadata?.TryGetValue("CustomMetadata", out var value) + ?? false) { if (string.IsNullOrEmpty(value)) { - context.Errors.Add(new ArgumentException("A non-empty CustomMetadata value is required")); + context.Errors.Add(new ArgumentException( + "A non-empty CustomMetadata value is required")); } } } @@ -150,17 +161,22 @@ internal class MyTransformProvider : ITransformProvider public void Apply(TransformBuilderContext transformBuildContext) { // Check all routes for a custom property and add the associated transform. - if ((transformBuildContext.Route.Metadata?.TryGetValue("CustomMetadata", out var value) ?? false) - || (transformBuildContext.Cluster?.Metadata?.TryGetValue("CustomMetadata", out value) ?? false)) + if ((transformBuildContext.Route.Metadata?.TryGetValue("CustomMetadata", + out var value) ?? false) + || (transformBuildContext.Cluster?.Metadata?.TryGetValue( + "CustomMetadata", out value) ?? false)) { if (string.IsNullOrEmpty(value)) { - throw new ArgumentException("A non-empty CustomMetadata value is required"); + throw new ArgumentException( + "A non-empty CustomMetadata value is required"); } transformBuildContext.AddRequestTransform(transformContext => { - transformContext.ProxyRequest.Options.Set(new HttpRequestOptionsKey("CustomMetadata"), value); + transformContext.ProxyRequest.Options.Set( + new HttpRequestOptionsKey("CustomMetadata"), value); + return default; }); } @@ -168,9 +184,9 @@ internal class MyTransformProvider : ITransformProvider } ``` -## ITransformFactory +## `ITransformFactory` -Developers that want to integrate their custom transforms with the `Transforms` section of configuration can implement an [ITransformFactory](xref:Yarp.ReverseProxy.Transforms.Builder.ITransformFactory). This should be registered in DI using the `AddTransformFactory()` method. Multiple factories can be registered and all will be used. +Developers that want to integrate their custom transforms with the `Transforms` section of configuration can implement an . This should be registered in DI using the `AddTransformFactory()` method. Multiple factories can be registered and all will be used. `ITransformFactory` provides two methods, `Validate` and `Build`. These process one set of transform values at a time, represented by a `IReadOnlyDictionary`. @@ -178,40 +194,47 @@ The `Validate` method is called when loading a configuration to verify the conte The `Build` method takes the given configuration and produces the associated transform instances for the route. -```C# +```csharp services.AddReverseProxy() .LoadFromConfig(_configuration.GetSection("ReverseProxy")) .AddTransformFactory(); ``` -```C# + +```csharp internal class MyTransformFactory : ITransformFactory { - public bool Validate(TransformRouteValidationContext context, IReadOnlyDictionary transformValues) + public bool Validate(TransformRouteValidationContext context, + IReadOnlyDictionary transformValues) { if (transformValues.TryGetValue("CustomTransform", out var value)) { if (string.IsNullOrEmpty(value)) { - context.Errors.Add(new ArgumentException("A non-empty CustomTransform value is required")); + context.Errors.Add(new ArgumentException( + "A non-empty CustomTransform value is required")); } return true; // Matched } + return false; } - public bool Build(TransformBuilderContext context, IReadOnlyDictionary transformValues) + public bool Build(TransformBuilderContext context, + IReadOnlyDictionary transformValues) { if (transformValues.TryGetValue("CustomTransform", out var value)) { if (string.IsNullOrEmpty(value)) { - throw new ArgumentException("A non-empty CustomTransform value is required"); + throw new ArgumentException( + "A non-empty CustomTransform value is required"); } context.AddRequestTransform(transformContext => { - transformContext.ProxyRequest.Options.Set(new HttpRequestOptionsKey("CustomTransform"), value); + transformContext.ProxyRequest.Options.Set( + new HttpRequestOptionsKey("CustomTransform"), value); return default; }); @@ -227,14 +250,16 @@ internal class MyTransformFactory : ITransformFactory Consider also adding parametrized extension methods on `RouteConfig` like `WithTransformQueryValue` to facilitate programmatic route construction. -```C# -public static RouteConfig WithTransformQueryValue(this RouteConfig routeConfig, string queryKey, string value, bool append = true) +```csharp +public static RouteConfig WithTransformQueryValue(this RouteConfig routeConfig, + string queryKey, string value, bool append = true) { - var type = append ? QueryTransformFactory.AppendKey : QueryTransformFactory.SetKey; + var type = append ? QueryTransformFactory.AppendKey : + QueryTransformFactory.SetKey; return routeConfig.WithTransform(transform => { transform[QueryTransformFactory.QueryValueParameterKey] = queryKey; transform[type] = value; }); } -``` \ No newline at end of file +``` diff --git a/aspnetcore/fundamentals/servers/yarp/extensibility.md b/aspnetcore/fundamentals/servers/yarp/extensibility.md index b0d4143d2536..0fd68f6ac197 100644 --- a/aspnetcore/fundamentals/servers/yarp/extensibility.md +++ b/aspnetcore/fundamentals/servers/yarp/extensibility.md @@ -9,7 +9,6 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- - # Overview of YARP extensibility There are 2 main styles of extensibility for YARP, depending on the routing behavior desired: @@ -23,24 +22,24 @@ YARP uses the concept of [Routes](xref:fundamentals/servers/yarp/config-files#ro ![Middleware pipeline diagram](~/fundamentals/servers/yarp/media/yarp-pipeline.png) -Most of the pre-built pipeline can be customized through code: +Most of the prebuilt pipeline can be customized through code: -- [Configuration Providers](xref:fundamentals/servers/yarp/config-providers) -- [Destination Enumeration](xref:fundamentals/servers/yarp/destination-resolvers) -- [Session Affinity](xref:fundamentals/servers/yarp/session-affinity) -- [Load Balancing](xref:fundamentals/servers/yarp/load-balancing) -- [Health Checks](xref:fundamentals/servers/yarp/dests-health-checks) -- [Request Transforms](xref:fundamentals/servers/yarp/transform-extensibility) -- [HttpClient configuration](./http-client-config.md#code-configuration) +* [Configuration Providers](xref:fundamentals/servers/yarp/config-providers) +* [Destination Enumeration](xref:fundamentals/servers/yarp/destination-resolvers) +* [Session Affinity](xref:fundamentals/servers/yarp/session-affinity) +* [Load Balancing](xref:fundamentals/servers/yarp/load-balancing) +* [Health Checks](xref:fundamentals/servers/yarp/dests-health-checks) +* [Request Transforms](xref:fundamentals/servers/yarp/transform-extensibility) +* [HttpClient configuration](./http-client-config.md#code-configuration) You can also change the pipeline definition to replace modules with your own implementation(s) or add additional modules as needed. For more information see [Middleware](xref:fundamentals/servers/yarp/middleware). -## Http Forwarder +## HTTP Forwarder -If the YARP pipeline is too rigid for your needs, or the scale of routing rules and destinations is not suitable for loading into memory, then you can implement your own routing logic and use the HTTP Forwarder to direct requests to your chosen destination. The HttpForwarder component takes the HTTP context and forwards the request to the supplied destination. +If the YARP pipeline is too rigid for your use case or the scale of routing rules and destinations isn't suitable for loading into memory, then you can implement your own routing logic and use the HTTP Forwarder to direct requests to your chosen destination. The `HttpForwarder` component takes the HTTP context and forwards the request to the supplied destination. ![HTTP forwarder diagram](~/fundamentals/servers/yarp/media/yarp-forwarder.png) -The transform component can still be used with the forwarder is needed. +The transform component can still be used if the forwarder is needed. For more information see [Direct forwarding](xref:fundamentals/servers/yarp/direct-forwarding). diff --git a/aspnetcore/fundamentals/servers/yarp/getting-started.md b/aspnetcore/fundamentals/servers/yarp/getting-started.md index ae8f4d9a1d1d..ef0e0369aee7 100644 --- a/aspnetcore/fundamentals/servers/yarp/getting-started.md +++ b/aspnetcore/fundamentals/servers/yarp/getting-started.md @@ -9,10 +9,9 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- +# Getting started with YARP -# Getting Started with YARP - -YARP is designed as a library that provides the core proxy functionality which you can then customize by adding or replacing modules. YARP is currently provided as a NuGet package and code snippets. We plan on providing a project template and prebuilt executable (`.exe`) in the future. +YARP is designed as a library that provides the core proxy functionality, which you can customize by adding or replacing modules. YARP is currently provided as a NuGet package and code samples. We plan on providing a project template and prebuilt executable (`.exe`) in the future. YARP is implemented on top of .NET Core infrastructure and is usable on Windows, Linux or MacOS. Development can be done with the SDK and your favorite editor, [Microsoft Visual Studio](https://visualstudio.microsoft.com/vs/) or [Visual Studio Code](https://code.visualstudio.com/). @@ -24,7 +23,7 @@ You can download the .NET SDK from https://dotnet.microsoft.com/download/dotnet/ A complete version of the project built using the steps below can be found at [Basic YARP Sample](https://github.com/microsoft/reverse-proxy/tree/release/latest/samples/BasicYarpSample). -Start by creating an "Empty" ASP.NET Core application using the command line: +Start by creating an empty ASP.NET Core application using the command line: ```dotnetcli dotnet new web -n MyProxy @@ -97,6 +96,6 @@ Learn more about the available configuration options by looking at `. +When using the .NET CLI, use `dotnet run` within the sample's directory or `dotnet run --project `. -In Visual Studio, start the app with the **Run** button. +In Visual Studio, start the app by clicking the **Run** button. diff --git a/aspnetcore/fundamentals/servers/yarp/grpc.md b/aspnetcore/fundamentals/servers/yarp/grpc.md index b223c65d41fc..e1e9756b801d 100644 --- a/aspnetcore/fundamentals/servers/yarp/grpc.md +++ b/aspnetcore/fundamentals/servers/yarp/grpc.md @@ -1,7 +1,7 @@ --- uid: fundamentals/servers/yarp/grpc -title: YARP Proxing gRPC -description: YARP Proxing gRPC +title: YARP Proxying gRPC +description: YARP Proxying gRPC author: samsp-msft ms.author: samsp ms.date: 2/6/2025 @@ -9,8 +9,7 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- - -# YARP Proxing gRPC +# YARP Proxying gRPC ## Introduction @@ -20,9 +19,10 @@ ai-usage: ai-assisted gRPC requires HTTP/2 for most scenarios. HTTP/1.1 and HTTP/2 are enabled by default on ASP.NET Core servers (YARP's front end) but they require https (TLS) for HTTP/2 so YARP needs to be listening on a `https://` URL. -HTTP/2 over http (non-TLS) is only supported on Kestrel and requires specific settings. For details see [here](/aspnet/core/grpc/aspnetcore#server-options). +HTTP/2 over http (non-TLS) is only supported on Kestrel and requires specific settings. For more information, see . This shows configuring Kestrel to use HTTP/2 over http (non-TLS): + ```json { "Kestrel": { @@ -38,9 +38,10 @@ This shows configuring Kestrel to use HTTP/2 over http (non-TLS): ## Configure YARP's Outgoing Protocols -YARP automatically negotiates HTTP/1.1 or HTTP/2 for outgoing proxy requests, but only for https (TLS). HTTP/2 over http (non-TLS) requires additional settings. Note outgoing protocols are independent of incoming ones. E.g. https can be used for the incoming connection and http for the outgoing one, this is called TLS termination. See [here](http-client-config.md#httprequest) for configuration details. +YARP automatically negotiates HTTP/1.1 or HTTP/2 for outgoing proxy requests, but only for https (TLS). HTTP/2 over http (non-TLS) requires additional settings. Note that outgoing protocols are independent of incoming ones. E.g. https can be used for the incoming connection and http for the outgoing one, this is called TLS termination. For configuration details, see . + +The following shows how to configure the outgoing proxy request to use HTTP/2: -This shows configuring the outgoing proxy request to use HTTP/2 over http. ```json "cluster1": { "HttpRequest": { diff --git a/aspnetcore/fundamentals/servers/yarp/header-guidelines.md b/aspnetcore/fundamentals/servers/yarp/header-guidelines.md index 6e086033fa20..e8c5f0297b2b 100644 --- a/aspnetcore/fundamentals/servers/yarp/header-guidelines.md +++ b/aspnetcore/fundamentals/servers/yarp/header-guidelines.md @@ -1,7 +1,7 @@ --- uid: fundamentals/servers/yarp/header-guidelines -title: YARP HTTP Headers -description: YARP HTTP Headers +title: YARP HTTP header guidelines +description: Learn about YARP HTTP header guidelines. author: samsp-msft ms.author: samsp ms.date: 2/6/2025 @@ -9,79 +9,81 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- +# YARP HTTP header guidelines -# YARP HTTP Headers - -Headers are a very important part of processing HTTP requests and each have their own semantics and considerations. Most headers are proxied by default, though some used to control how the request is delivered are automatically adjusted or removed by the proxy. The connections between the client and the proxy and the proxy and destination are independent, and so headers that affect the connection and transport need to be filtered. Many headers contain information like domain names, paths, or other details that may be affected when a reverse proxy is included in the application architecture. Below is a collection of guidelines about how specific headers might be impacted and what to do about them. +Headers are a very important part of processing HTTP requests and each have their own semantics and considerations. Most headers are proxied by default, though some used to control how the request is delivered are automatically adjusted or removed by the proxy. The connections between the client and the proxy and between the proxy and the destination are independent. Therefore, headers that affect the connection and transport must be filtered. Many headers contain information like domain names, paths, or other details that may be affected when a reverse proxy is included in the application architecture. The following is a collection of guidelines about how specific headers might be impacted and what to do about them. ## YARP header filtering YARP automatically removes request and response headers that could impact its ability to forward a request correctly, or that may be used maliciously to bypass features of the proxy. A complete list can be found [here](https://github.com/microsoft/reverse-proxy/blob/main/src/ReverseProxy/Forwarder/RequestUtilities.cs#L71), with some highlights described below. -### Connection, KeepAlive, Close +### `Connection`, `KeepAlive`, `Close` -These headers control how the TCP connection is managed and are removed to avoid impacting the connection on the other side of the proxy. +These headers control how the TCP connection is managed and are removed to prevent impacting the connection on the other side of the proxy. -### Transfer-Encoding +### `Transfer-Encoding` This header describes the format of the request or response body on the wire, e.g. 'chunked', and is removed because the format can vary between the internal and external connection. The incoming and outgoing HTTP stacks will add transport headers as needed. -### TE +### `TE` Only the `TE: trailers` header value is allowed through the proxy since it's required for some gRPC implementations. -### Upgrade +### `Upgrade` This is used for protocols like WebSockets. It is removed by default and only added back for specifically supported protocols (WebSockets, SPDY). -### Proxy-* +### `Proxy-*` These are headers used with proxies and are not considered appropriate to forward. -### Alt-Svc +### `Alt-Svc` This response header is used with HTTP/3 upgrades and only applies to the immediate connection. ### Distributed tracing headers -These headers include TraceParent, Request-Id, TraceState, Baggage, Correlation-Context. -They are automatically removed based on `DistributedContextPropagator.Fields` so that the forwarding HttpClient can replace them with updated values. -You can opt out of modifying these headers by setting `SocketsHttpHandler.ActivityHeadersPropagator` to `null`: -```C# +These headers include `TraceParent`, `Request-Id`, `TraceState`, `Baggage`, and `Correlation-Context`. + +They're automatically removed based on , allowing the forwarding to replace them with updated values. + +You can opt out of modifying these headers by setting to `null`: + +```csharp services.AddReverseProxy() .ConfigureHttpClient((_, handler) => handler.ActivityHeadersPropagator = null); ``` -### Strict-Transport-Security +### `Strict-Transport-Security` This header instructs clients to always use HTTPS, but there may be a conflict between values provided by the proxy and destination. To avoid confusion, the destination's value is not copied to the response if one was already added to the response by the proxy application. -## Other Header Guidelines +## Other header guidelines -### Host +### `Host` -The Host header indicates which site on the server the request is intended for. This header is removed by default since the host name used publicly by the proxy is likely to differ from the one used by the service behind the proxy. This is configurable using the [RequestHeaderOriginalHost](xref:fundamentals/servers/yarp/transforms#requestheaderoriginalhost) transform. +The Host header indicates which site on the server the request is intended for. This header is removed by default since the host name used publicly by the proxy is likely to differ from the one used by the service behind the proxy. This can be configured using the [`RequestHeaderOriginalHost`](xref:fundamentals/servers/yarp/transforms#requestheaderoriginalhost) transform. -### X-Forwarded-*, Forwarded +### `X-Forwarded-*`, `Forwarded` -Because a separate connection is used to communicate with the destination, these request headers can be used to forward information about the original connection like the IP, scheme, port, client certificate, etc.. X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-Prefix are enabled by default. This information is subject to spoofing attacks so any existing headers on the request are removed and replaced by default. The destination app should be careful about how much trust it places in these values. See [transforms](xref:fundamentals/servers/yarp/transforms#defaults) for configuring these in the proxy. See the [ASP.NET docs](/aspnet/core/host-and-deploy/proxy-load-balancer) for configuring the destination app to read these headers. +Because a separate connection is used to communicate with the destination, these request headers can be used to forward information about the original connection, such as the IP, scheme, port, and client certificate. `X-Forwarded-For`, `X-Forwarded-Proto`, `X-Forwarded-Host`, and `X-Forwarded-Prefix` are enabled by default. This information is subject to spoofing attacks so any existing headers on the request are removed and replaced by default. The destination app should be careful about how much trust it places in these values. See [transforms](xref:fundamentals/servers/yarp/transforms#defaults) for configuring these in the proxy. For guidance on configuring the destination app to read these headers, see . -### X-http-method-override, x-http-method, x-method-override +### `X-http-method-override`, `x-http-method`, `x-method-override` -Some clients and servers limit which HTTP methods they allow (GET, POST, etc.). These request headers are sometimes used to work around those restrictions. These headers are proxied by default. If in the proxy you want to prevent these bypasses then use the [RequestHeaderRemove](xref:fundamentals/servers/yarp/transforms#requestheaderremove) transform. +Some clients and servers limit which HTTP methods they allow (for example, GET). These request headers are sometimes used to work around those restrictions. These headers are proxied by default. If in the proxy you want to prevent these bypasses then use the [RequestHeaderRemove](xref:fundamentals/servers/yarp/transforms#requestheaderremove) transform. -### Set-Cookie +### `Set-Cookie` -This response header may contain fields constraining the path, domain, scheme, etc. where the cookie should be used. Using a reverse proxy may change the effective domain, path, or scheme of a site from the public view. While it would be possible to [rewrite](https://github.com/microsoft/reverse-proxy/issues/1109) response cookies using custom transforms, it's recommended instead to use the Forwarded headers described above to flow the correct values to the destination app so it can generate the correct set-cookie headers. +This response header may contain fields that constrain aspects of the URL, such as the scheme, domain, or path, where the cookie should be used. Using a reverse proxy may change the effective scheme, domain, or path of a site from the public view. While it would be possible to [rewrite response cookies using custom transforms](https://github.com/microsoft/reverse-proxy/issues/1109), we recommended instead to use the `Forwarded` headers described earlier to flow the correct values to the destination app so it can generate the correct `set-cookie` headers. -### Location +### `Location` This response header is used with redirects and may contain a scheme, domain, and path that differ from the public values due to the use of the proxy. While it would be possible to [rewrite](https://github.com/microsoft/reverse-proxy/discussions/466) the Location header using custom transforms, it's recommended instead to use the Forwarded headers described above to flow the correct values to the destination app so it can generate the correct Location headers. -### Server +### `Server` -This response header indicates what server technology was used to generate the response (IIS, Kestrel, etc.). This header is proxied from the destination by default. Applications that want to remove it can use the [ResponseHeaderRemove](xref:fundamentals/servers/yarp/transforms#responseheaderremove) transform, in which case the proxy's default server header will be used. Suppressing the proxy default server header is server specific, such as for [Kestrel](/dotnet/api/microsoft.aspnetcore.server.kestrel.core.kestrelserveroptions.addserverheader#Microsoft_AspNetCore_Server_Kestrel_Core_KestrelServerOptions_AddServerHeader). +This response header indicates what server technology was used to generate the response (for example, IIS, Kestrel). This header is proxied from the destination by default. Applications that want to remove it can use the [ResponseHeaderRemove](xref:fundamentals/servers/yarp/transforms#responseheaderremove) transform, in which case the proxy's default server header will be used. Suppressing the proxy default server header is server specific, such as for [Kestrel](/dotnet/api/microsoft.aspnetcore.server.kestrel.core.kestrelserveroptions.addserverheader#Microsoft_AspNetCore_Server_Kestrel_Core_KestrelServerOptions_AddServerHeader). -### X-Powered-By +### `X-Powered-By` -This response header indicates what web framework was used to generate the response (ASP.NET, etc.). ASP.NET Core does not generate this header but IIS can. This header is proxied from the destination by default. Applications that want to remove it can use the [ResponseHeaderRemove](xref:fundamentals/servers/yarp/transforms#responseheaderremove) transform. +This response header indicates what web framework was used to generate the response (for example, ASP.NET). ASP.NET Core does not generate this header but IIS can. This header is proxied from the destination by default. Applications that want to remove it can use the [ResponseHeaderRemove](xref:fundamentals/servers/yarp/transforms#responseheaderremove) transform. diff --git a/aspnetcore/fundamentals/servers/yarp/http-client-config.md b/aspnetcore/fundamentals/servers/yarp/http-client-config.md index 98a851e9df0b..ca1c05e6ae0a 100644 --- a/aspnetcore/fundamentals/servers/yarp/http-client-config.md +++ b/aspnetcore/fundamentals/servers/yarp/http-client-config.md @@ -26,7 +26,7 @@ These types are focused on defining serializable configuration. The code based c ### HttpClient HTTP client configuration is based on [HttpClientConfig](xref:Yarp.ReverseProxy.Configuration.HttpClientConfig) and represented by the following configuration schema. If you need a more granular approach, use a [custom implementation](xref:fundamentals/servers/yarp/http-client-config#custom-iforwarderhttpclientfactory) of `IForwarderHttpClientFactory`. - + ```JSON "HttpClient": { "SslProtocols": [ "" ], diff --git a/aspnetcore/fundamentals/servers/yarp/httpsys-delegation.md b/aspnetcore/fundamentals/servers/yarp/httpsys-delegation.md index c0d8705cf889..4d90cf0c9c09 100644 --- a/aspnetcore/fundamentals/servers/yarp/httpsys-delegation.md +++ b/aspnetcore/fundamentals/servers/yarp/httpsys-delegation.md @@ -1,7 +1,7 @@ --- uid: fundamentals/servers/yarp/httpsys-delegation -title: YARP Http.sys Delegation -description: YARP Http.sys Delegation +title: YARP HTTP.sys Delegation +description: YARP HTTP.sys Delegation author: samsp-msft ms.author: samsp ms.date: 2/6/2025 @@ -9,22 +9,26 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- - -# YARP Http.sys Delegation +# YARP HTTP.sys Delegation ## Introduction -Http.sys delegation is a kernel level feature added into newer versions of Windows which allows a request to be transferred from the receiving process's http.sys queue to a target process's http.sys queue with very little overhead or added latency. For this delegation to work, the receiving process is only allowed to read the request headers. If the body has started to be read or a response has started, trying to delegate the request will fail. The response will not be visible to the proxy after delegation, which limits the functionality of the session affinity and passive health checks components, as well as some of the load balancing algorithms. Internally, YARP leverage's ASP.NET Core's [IHttpSysRequestDelegationFeature](/dotnet/api/microsoft.aspnetcore.server.httpsys.ihttpsysrequestdelegationfeature) + +HTTP.sys delegation is a kernel level feature added into newer versions of Windows which allows a request to be transferred from the receiving process's HTTP.sys queue to a target process's HTTP.sys queue with very little overhead or added latency. For this delegation to work, the receiving process is only allowed to read the request headers. If the body has started to be read or a response has started, trying to delegate the request will fail. The response will not be visible to the proxy after delegation, which limits the functionality of the session affinity and passive health checks components, as well as some of the load balancing algorithms. Internally, YARP leverages ASP.NET Core's [IHttpSysRequestDelegationFeature](/dotnet/api/microsoft.aspnetcore.server.httpsys.ihttpsysrequestdelegationfeature) ## Requirements -Http.sys delegation requires: -- [ASP.NET Core's Http.sys server](/aspnet/core/fundamentals/servers/httpsys) -- Windows Server 2019 or Windows 10 (build number 1809) or newer. + +HTTP.sys delegation requires: + +* [ASP.NET Core's HTTP.sys server](/aspnet/core/fundamentals/servers/httpsys) +* Windows Server 2019 or Windows 10 (build number 1809) or newer. ## Defaults -Http.sys delegation won't be used unless added to the proxy pipeline and enabled in the destination configuration. + +HTTP.sys delegation won't be used unless added to the proxy pipeline and enabled in the destination configuration. ## Configuration -Http.sys delegation can be enabled per destination by adding the `HttpSysDelegationQueue` metadata to the destination. The value of this metadata should be the target http.sys queue name. The destination's Address is used to specify the url prefix of the http.sys queue. + +HTTP.sys delegation can be enabled per destination by adding the `HttpSysDelegationQueue` metadata to the destination. The value of this metadata should be the target HTTP.sys queue name. The destination's Address is used to specify the url prefix of the HTTP.sys queue. ```json { @@ -53,31 +57,35 @@ Http.sys delegation can be enabled per destination by adding the `HttpSysDelegat } ``` -In host configuration, configure the host to use the Http.sys server. -```c# +In host configuration, configure the host to use the HTTP.sys server: + +```csharp webBuilder.UseHttpSys(); ``` -In application configuration, use the `MapReverseProxy` overload that lets you customize the pipeline and add http.sys delegation by calling `UseHttpSysDelegation`. -```c# +In application configuration, use the `MapReverseProxy` overload that allows you to customize the pipeline and add HTTP.sys delegation by calling `UseHttpSysDelegation`: + +```csharp app.MapReverseProxy(proxyPipeline => { - // Add the three middleware YARP adds by default plus the Http.sys delegation middleware - proxyPipeline.UseSessionAffinity(); // Has no affect on delegation destinations + // Add the three middleware YARP adds by default plus the HTTP.sys + // delegation middleware + proxyPipeline.UseSessionAffinity(); // No affect on delegation destinations proxyPipeline.UseLoadBalancing(); proxyPipeline.UsePassiveHealthChecks(); proxyPipeline.UseHttpSysDelegation(); }); ``` -## Delegation Queue Lifetime -When YARP is configured to use delegation for a destination, a handle is created to the specified http.sys queue. This handle is kept alive as long as the destinations referencing it exist. Clean up of these handles is done during GC, so it's possible cleanup of the handle is delayed if it ends up in Gen2. This may cause issues for some receivers during process restart because if they try to create the queue during startup it will fail (because it still exists since YARP has a handle to it). The receivers need to be smart enough to attach instead and propertly re-setup the queue. ASP.NET Core's http.sys server [has this issue](https://github.com/dotnet/aspnetcore/issues/40359). +## Delegation queue lifetime + +When YARP is configured to use delegation for a destination, a handle is created to the specified HTTP.sys queue. This handle is kept alive as long as the destinations referencing it exist. Clean up of these handles is done during GC, so it's possible cleanup of the handle is delayed if it ends up in Gen2. This may cause issues for some receivers during process restart because if they try to create the queue during startup it fails because it still exists since YARP has a handle to it. The receivers must be smart enough to attach instead and properly re-setup the queue. ASP.NET Core's HTTP.sys server has this issue. For more information, see [Http.sys server should support setting up URL groups when attaching to an existing queue (`dotnet/aspnetcore` #40359)](https://github.com/dotnet/aspnetcore/issues/40359). -YARP exposes a way to reset its handle to the queue. This allows consumers to write custom logic to determin if/when the handle to the queue should be cleaned up. +YARP exposes a way to reset its handle to the queue. This allows consumers to write custom logic to determine when the handle to the queue should be cleaned up. Example: -```c# +```csharp var delegator = app.Services.GetRequiredService(); delegator.ResetQueue("TargetHttpSysQueueName", "http://*:80"); ``` diff --git a/aspnetcore/fundamentals/servers/yarp/kubernetes-ingress.md b/aspnetcore/fundamentals/servers/yarp/kubernetes-ingress.md index 0e30bdb8af38..febe309ce817 100644 --- a/aspnetcore/fundamentals/servers/yarp/kubernetes-ingress.md +++ b/aspnetcore/fundamentals/servers/yarp/kubernetes-ingress.md @@ -9,7 +9,6 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- - # YARP Kubernetes Ingress Controller Introduced: Future Preview @@ -20,33 +19,36 @@ YARP can be integrated with Kubernetes as a reverse proxy managing HTTP/HTTPS tr Before we continue with this tutorial, make sure you have the following ready... -1. Installing [docker](https://docs.docker.com/install/) based on your operating system. +1. Installing [Docker](https://docs.docker.com/install/) based on your operating system. + +1. A container registry. Docker by default will create a container registry on [DockerHub](https://hub.docker.com/). You could also use [Azure Container Registry](/en-us/azure/aks/tutorial-kubernetes-prepare-acr) or another container registry of your choice, like a [local registry](https://docs.docker.com/registry/deploying/#run-a-local-registry) for testing. -2. A container registry. Docker by default will create a container registry on [DockerHub](https://hub.docker.com/). You could also use [Azure Container Registry](/en-us/azure/aks/tutorial-kubernetes-prepare-acr) or another container registry of your choice, like a [local registry](https://docs.docker.com/registry/deploying/#run-a-local-registry) for testing. +1. A Kubernetes Cluster. There are many different options here, including: -3. A Kubernetes Cluster. There are many different options here, including: - - [Azure Kubernetes Service](/en-us/azure/aks/tutorial-kubernetes-deploy-cluster) - - [Kubernetes in Docker Desktop](https://www.docker.com/blog/docker-windows-desktop-now-kubernetes/), however it does take up quite a bit of memory on your machine, so use with caution. - - [Minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/) - - [K3s](https://k3s.io), a lightweight single-binary certified Kubernetes distribution from Rancher. - - Another Kubernetes provider of your choice. + * [Azure Kubernetes Service](/en-us/azure/aks/tutorial-kubernetes-deploy-cluster) + * [Kubernetes in Docker Desktop](https://www.docker.com/blog/docker-windows-desktop-now-kubernetes/), however it does take up quite a bit of memory on your machine, so use with caution. + * [Minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/) + * [K3s](https://k3s.io), a lightweight single-binary certified Kubernetes distribution from Rancher. + * Another Kubernetes provider of your choice. -> :warning: If you choose a container registry provided by a cloud provider (other than Dockerhub), you will likely have to take some steps to configure your kubernetes cluster to allow access. Follow the instructions provided by your cloud provider. +> [!NOTE] +> If you choose a container registry provided by a cloud provider other than Dockerhub, you probably must take steps to configure your Kubernetes cluster to allow access. Follow the instructions provided by your cloud provider. -## Get Started +## Get started -> :warning: For now there is no official docker image for the YARP ingress controller. +> [!NOTE] +> For now, there is no official Docker image for the YARP ingress controller. -So, in the meantime we need to build the YARP ingress controller locally and deploy it. In the root of the repository, run: +In the meantime, the YARP ingress controller must be built locally and deploy it. In the root of the repository, run: ``` -docker build . -t /yarp-controller: -f .\src\Kubernetes.Controller\Dockerfile -docker push /yarp-controller: +docker build . -t {REGISTRY_NAME}/yarp-controller:{TAG} -f .\src\Kubernetes.Controller\Dockerfile +docker push {REGISTRY_NAME}/yarp-controller:{TAG} ``` -where `REGISTRY_NAME` is the name of your docker registry and `TAG` is a tag for the image (for example 1.0.0). +In the preceding commands, the `{REGISTRY_NAME}` placeholder is the name of the Docker registry, and the `{TAG}` placeholder is a tag for the image (for example, `1.0.0`). -Then the first step will be to deploy the YARP ingress controller to the Kubernetes cluster. This can be done by navigating to [Kubernetes Ingress sample](https://github.com/dotnet/yarp/tree/release/latest/samples/KubernetesIngress.Sample) `\samples\KuberenetesIngress.Sample\Ingress` +The first step is to deploy the YARP ingress controller to the Kubernetes cluster. This can be done by navigating to [Kubernetes Ingress sample](https://github.com/dotnet/yarp/tree/release/latest/samples/KubernetesIngress.Sample) `\samples\KubernetesIngress.Sample\Ingress` and running (after modifying `ingress-controller.yaml` with the same `REGISTRY_NAME` and `TAG`): ``` @@ -62,21 +64,21 @@ kubectl get pods -n yarp You can then check logs from the ingress controller by running: ``` -kubectl logs -n yarp +kubectl logs {POD NAME} -n yarp ``` -> :bulb: All services, deployments, and pods for YARP are in the namespace `yarp`. Make sure to include `-n yarp` if you want to check on the status of yarp. +All services, deployments, and pods for YARP are in the namespace `yarp`. Make sure to include `-n yarp` if you want to check on the status of yarp. -Next, we need to build and deploy our ingress. In the root of the repository, run: +Next, build and deploy the ingress. In the root of the repository, run: ``` -docker build . -t /yarp: -f .\samples\KuberenetesIngress.Sample\Ingress\Dockerfile -docker push /yarp: +docker build . -t {REGISTRY_NAME}/yarp: -f .\samples\KuberenetesIngress.Sample\Ingress\Dockerfile +docker push {REGISTRY_NAME}/yarp:{TAG} ``` -where `REGISTRY_NAME` is the name of your docker registry and `TAG` is a tag for the image (for example 1.0.0). +In the preceding commands, the `{REGISTRY_NAME}` placeholder is the name of the Docker registry, and the `{TAG}` placeholder is a tag for the image (for example, `1.0.0`). -Finally, we need to deploy the ingress itself to Kubernetes. To do this navigate again to the `Ingress` directory, modify the `ingress.yaml` file for your registry and tag specified earlier and run: +Finally, we need to deploy the ingress itself to Kubernetes. Navigate to the `Ingress` directory and modify the `ingress.yaml` file for your registry and tag specified earlier and run: ``` kubectl apply -f .\ingress.yaml @@ -89,11 +91,11 @@ At this point, your ingress and controller should be running. To use the ingress, we now need to deploy an application to Kubernetes. Navigate to `samples\KuberenetesIngress.Sample\backend` and run: ``` -docker build . -t /backend: -docker push /backend: +docker build . -t {REGISTRY_NAME}/backend:{TAG} +docker push {REGISTRY_NAME}/backend:{TAG} ``` -And deploying it to kubernetes by running (after modifying `backend.yaml` with the same `REGISTRY_NAME` and `TAG`): +And deploying it to Kubernetes by running, after modifying `backend.yaml` with the same registry name (`{REGISTRY_NAME}`) and tag (`{TAG}`): ``` kubectl apply -f .\backend.yaml @@ -107,15 +109,12 @@ Finally, once we have deployed the backend application, we need to route traffic kubectl apply -f .\ingress-sample.yaml ``` -And then run: +And then execute the following command to get the external IP of the ingress, the name of the related service being `yarp-proxy`: ``` - kubectl get service -n yarp +kubectl get service -n yarp ``` -to get the external IP of the ingress, the name of the related service being `yarp-proxy`. - -> :bulb: If you are using a local K8s cluster and don't get an external IP, you may need to not use the default `port: 80` for the `yarp-proxy` service. -If so, try to update again the `ingress.yaml` file to use another port e.g. `port: 8085` and then re-deploy the ingress to Kubernetes. +If you're using a local K8s cluster and don't get an external IP, you may be able to avoid using the default `port: 80` for the `yarp-proxy` service. If so, try to update the `ingress.yaml` file again to use another port (for example, `port: 8085`) and redeploy the ingress to Kubernetes. Navigate to the external IP, and you should see the backend information. diff --git a/aspnetcore/fundamentals/servers/yarp/load-balancing.md b/aspnetcore/fundamentals/servers/yarp/load-balancing.md index 8fc96975e68d..5b751ad83eaa 100644 --- a/aspnetcore/fundamentals/servers/yarp/load-balancing.md +++ b/aspnetcore/fundamentals/servers/yarp/load-balancing.md @@ -72,22 +72,27 @@ var clusters = new[] ## Built-in policies YARP ships with the following built-in policies: + - `FirstAlphabetical` - Select the alphabetically first available destination without considering load. This is useful for dual destination fail-over systems. +Select the alphabetically first available destination without considering load. This is useful for dual destination fail-over systems. + - `Random` - Select a destination randomly. +Select a destination randomly. + - `PowerOfTwoChoices` (default) - Select two random destinations and then select the one with the least assigned requests. - This avoids the overhead of `LeastRequests` and the worst case for `Random` where it selects a busy destination. +Select two random destinations and then select the one with the least assigned requests. +This avoids the overhead of `LeastRequests` and the worst case for `Random` where it selects a busy destination. + - `RoundRobin` - Select a destination by cycling through them in order. +Select a destination by cycling through them in order. + - `LeastRequests` - Select the destination with the least assigned requests. This requires examining all destinations. +Select the destination with the least assigned requests. This requires examining all destinations. ## Extensibility diff --git a/aspnetcore/fundamentals/servers/yarp/middleware.md b/aspnetcore/fundamentals/servers/yarp/middleware.md index df3de74f0b96..59dc3e3992ce 100644 --- a/aspnetcore/fundamentals/servers/yarp/middleware.md +++ b/aspnetcore/fundamentals/servers/yarp/middleware.md @@ -28,7 +28,7 @@ app.MapReverseProxy(); app.Run(); ``` -The parmeterless `MapReverseProxy()` in [ReverseProxyIEndpointRouteBuilderExtensions](xref:Microsoft.AspNetCore.Builder.ReverseProxyIEndpointRouteBuilderExtensions) overload includes all standard proxy middleware for [session affinity](xref:fundamentals/servers/yarp/session-affinity), [load balancing](xref:fundamentals/servers/yarp/load-balancing), [passive health checks](dests-health-checks.md#passive-health-checks), and the final proxying of the request. Each of these check the configuration of the matched route, cluster, and destination and perform their task accordingly. +The parameterless `MapReverseProxy()` in [ReverseProxyIEndpointRouteBuilderExtensions](xref:Microsoft.AspNetCore.Builder.ReverseProxyIEndpointRouteBuilderExtensions) overload includes all standard proxy middleware for [session affinity](xref:fundamentals/servers/yarp/session-affinity), [load balancing](xref:fundamentals/servers/yarp/load-balancing), [passive health checks](dests-health-checks.md#passive-health-checks), and the final proxying of the request. Each of these check the configuration of the matched route, cluster, and destination and perform their task accordingly. ## Adding Middleware @@ -112,7 +112,7 @@ Middleware like session affinity and load balancing examine the `IReverseProxyFe `AvailableDestinations` lists the destinations currently considered eligible to handle the request. It is initialized to `AllDestinations`, excluding unhealthy ones if health checks are enabled. `AvailableDestinations` should be reduced to a single destination by the end of the pipeline or else one will be selected randomly from the remainder. -`ProxiedDestination` is set by the proxy logic at the end of the pipeline to indicate which destination was ultimately used. If there are no available destinations remaining then a 503 error response is sent. +`ProxiedDestination` is set by the proxy logic at the end of the pipeline to indicate which destination was ultimately used. If there are no available destinations remaining then a 503 error response is sent. ```C# proxyPipeline.Use(async (context, next) => diff --git a/aspnetcore/fundamentals/servers/yarp/service-fabric-int.md b/aspnetcore/fundamentals/servers/yarp/service-fabric-int.md index 5fe8fc329be0..6422600ae170 100644 --- a/aspnetcore/fundamentals/servers/yarp/service-fabric-int.md +++ b/aspnetcore/fundamentals/servers/yarp/service-fabric-int.md @@ -9,7 +9,6 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- - # YARP Service Fabric Integration -This functionality has been replaced by https://github.com/microsoft/service-fabric-yarp +This functionality has been deprecated in favor of [`service-fabric-yarp` (GitHub repository)](https://github.com/microsoft/service-fabric-yarp). diff --git a/aspnetcore/fundamentals/servers/yarp/session-affinity.md b/aspnetcore/fundamentals/servers/yarp/session-affinity.md index 1aabe9e1584b..46c9021c3619 100644 --- a/aspnetcore/fundamentals/servers/yarp/session-affinity.md +++ b/aspnetcore/fundamentals/servers/yarp/session-affinity.md @@ -118,7 +118,7 @@ The `Cookie` and `CustomHeader` policies encrypt the key using Data Protection. ## Affinity failure policy If the affinity key cannot be decoded or no healthy destination found it's considered as a failure and an affinity failure policy is called to handle it. The policy has the full access to `HttpContext` and can send response to the client by itself. It returns a boolean value indicating whether the request processing can proceed down the pipeline or must be terminated. -There are two built-in failure policies. The default is `Redistribute`. +There are two built-in failure policies. The default is `Redistribute`. 1. `Redistribute` - tries to establish a new affinity to one of available healthy destinations by skipping the affinity lookup step and passing all healthy destination to the load balancer the same way it is done for a request without any affinity. Request processing continues. This is implemented by `RedistributeAffinityFailurePolicy`. 2. `Return503Error` - sends a `503` response back to the client and request processing is terminated. This is implemented by `Return503ErrorAffinityFailurePolicy` diff --git a/aspnetcore/fundamentals/servers/yarp/timeouts.md b/aspnetcore/fundamentals/servers/yarp/timeouts.md index 51283425ffa9..b9880ca063e4 100644 --- a/aspnetcore/fundamentals/servers/yarp/timeouts.md +++ b/aspnetcore/fundamentals/servers/yarp/timeouts.md @@ -22,7 +22,7 @@ Requests do not have any timeouts by default, other than the [Activity Timeout]( ## Configuration Timeouts and Timeout Policies can be specified per route via [RouteConfig](xref:Yarp.ReverseProxy.Configuration.RouteConfig) and can be bound from the `Routes` sections of the config file. As with other route properties, this can be modified and reloaded without restarting the proxy. Policy names are case insensitive. -Timeouts are specified in a TimeSpan HH:MM:SS format. Specifying both Timeout and TimeoutPolicy on the same route is invalid and will cause the configuration to be rejected. +Timeouts are specified in a TimeSpan format (HH:MM:SS). Specifying both a Timeout and a TimeoutPolicy on the same route is invalid and will cause the configuration to be rejected. Note that request timeouts do not apply when a debugger is attached to the process. diff --git a/aspnetcore/fundamentals/servers/yarp/transforms-response.md b/aspnetcore/fundamentals/servers/yarp/transforms-response.md index c9b0de5d9cfe..709aad158312 100644 --- a/aspnetcore/fundamentals/servers/yarp/transforms-response.md +++ b/aspnetcore/fundamentals/servers/yarp/transforms-response.md @@ -1,7 +1,7 @@ --- uid: fundamentals/servers/yarp/transforms-response title: YARP Response and Response Trailer Transforms -description: YARP Response and Response Trailer Transforms +description: YARP Response and Response Trailer Transforms author: samsp-msft ms.author: samsp ms.date: 2/6/2025 diff --git a/aspnetcore/fundamentals/servers/yarp/transforms.md b/aspnetcore/fundamentals/servers/yarp/transforms.md index 7f43723694b2..cbeae5a4b269 100644 --- a/aspnetcore/fundamentals/servers/yarp/transforms.md +++ b/aspnetcore/fundamentals/servers/yarp/transforms.md @@ -45,7 +45,7 @@ X-Forwarded-Host: IncomingHost:5000 ## Transform Categories -Transforms fall into a few categories: [Request](./transforms-request.md), [Response](./transforms-response.md), and [Response Trailers](./transforms-response.md#responsetrailer). Request trailers are not supported because they are not supported by the underlying HttpClient. +Transforms fall into a few categories: [Request](./transforms-request.md), [Response](./transforms-response.md), and [Response Trailers](./transforms-response.md#responsetrailer). Request trailers are not supported because they are not supported by the underlying HttpClient. If the built-in set of transforms is insufficient, then custom transforms can be added via [extensibility](./extensibility-transforms.md). diff --git a/aspnetcore/fundamentals/servers/yarp/websockets.md b/aspnetcore/fundamentals/servers/yarp/websockets.md index b53c09d757d4..d1fd9dcd47c7 100644 --- a/aspnetcore/fundamentals/servers/yarp/websockets.md +++ b/aspnetcore/fundamentals/servers/yarp/websockets.md @@ -1,7 +1,7 @@ --- uid: fundamentals/servers/yarp/websockets -title: YARP Proxing WebSockets and SPDY -description: YARP Proxing WebSockets and SPDY +title: YARP Proxying WebSockets and SPDY +description: YARP Proxying WebSockets and SPDY author: samsp-msft ms.author: samsp ms.date: 2/6/2025 @@ -9,8 +9,7 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- - -# YARP Proxing WebSockets and SPDY +# YARP Proxying WebSockets and SPDY ## Introduction diff --git a/aspnetcore/fundamentals/servers/yarp/yarp-overview.md b/aspnetcore/fundamentals/servers/yarp/yarp-overview.md index c9b41a4c158e..affcd3066fbc 100644 --- a/aspnetcore/fundamentals/servers/yarp/yarp-overview.md +++ b/aspnetcore/fundamentals/servers/yarp/yarp-overview.md @@ -9,7 +9,6 @@ ms.topic: article content_well_notification: AI-contribution ai-usage: ai-assisted --- - # Overview of YARP ## Introduction to YARP @@ -20,31 +19,30 @@ YARP (Yet Another Reverse Proxy) is a highly customizable reverse proxy library A reverse proxy is a server that sits between client devices and backend servers. It forwards client requests to the appropriate backend server and then returns the server's response to the client. A reverse proxy provides several benefits: -- Routing: Directs requests to different backend servers based on predefined rules, such as URL patterns or request headers. For example, `/images`, `/api`, `/db` requests can be can be routed image, api, and database severs. -- Load Balancing: Distributes incoming traffic across multiple backend servers to prevent overloading a specific server. Distribution increases performance and reliability. -- Scalability: By distributing traffic across multiple servers, a reverse proxy helps scale apps to handle more users and higher loads. Backend servers scaled (added or removed) without impacting the client. - -- [SSL/TLS Termination](/azure/application-gateway/ssl-overview): Offloads the TLS encryption and decryption processes from backend servers, reducing their workload. -- Connection abstraction, decoupling and control over URL-space: Inbound requests from external clients and outbound responses from the backend are independent. This independence allows for differnt: - - Versions of HTTP, ie, HTTP/1.1, HTTP/2, HTTP/3. The proxy can upgrade or downgrade HTTP versions. - - Connection lifetimes, which enables having long-lived connections on the backend while maintaining short client connections. - - Control Over URL-Space: Incoming URLs can be transformed before forwarding to the backend. This abstracts the external URLs from how they are mapped to internal services. Internal service endpoints can change without affecting external URLs. -- Security: Internal service endpoints can be hidden from external exposure, protecting against some types of cyber attacks such as [DDoS attacks](https://www.microsoft.com/security/business/security-101/what-is-a-ddos-attack?msockid=3e35ed3aa4666d8003aaf830a5006c74). -- Caching: Frequently requested resources can be cached to reduce the load on backend servers and improve response times. -- Versioning: Different versions of an API can be supported using different URL mappings. -- Simplified maintenance: Reverse proxies can handle [SSL/TLS Termination](/azure/application-gateway/ssl-overview) and other tasks, simplifying the configuration and maintenance of backend servers. For example, SSL certificates and security policies can be managed at the reverse proxy level instead of on each individual server. +* Routing: Directs requests to different backend servers based on predefined rules, such as URL patterns or request headers. For example, `/images`, `/api`, and `/db` requests can be routed image, api, and database servers. +* Load Balancing: Distributes incoming traffic across multiple backend servers to prevent overloading a specific server. Distribution increases performance and reliability. +* Scalability: By distributing traffic across multiple servers, a reverse proxy helps scale apps to handle more users and higher loads. Backend servers scaled (added or removed) without impacting the client. +* [SSL/TLS Termination](/azure/application-gateway/ssl-overview): Offloads the TLS encryption and decryption processes from backend servers, reducing their workload. +* Connection abstraction, decoupling and control over URL-space: Inbound requests from external clients and outbound responses from the backend are independent. This independence allows for differnt: + * Versions of HTTP, ie, HTTP/1.1, HTTP/2, HTTP/3. The proxy can upgrade or downgrade HTTP versions. + * Connection lifetimes, which enables having long-lived connections on the backend while maintaining short client connections. + * Control Over URL-Space: Incoming URLs can be transformed before forwarding to the backend. This abstracts the external URLs from how they are mapped to internal services. Internal service endpoints can change without affecting external URLs. +* Security: Internal service endpoints can be hidden from external exposure, protecting against some types of cyber attacks such as [DDoS attacks](https://www.microsoft.com/security/business/security-101/what-is-a-ddos-attack?msockid=3e35ed3aa4666d8003aaf830a5006c74). +* Caching: Frequently requested resources can be cached to reduce the load on backend servers and improve response times. +* Versioning: Different versions of an API can be supported using different URL mappings. +* Simplified maintenance: Reverse proxies can handle [SSL/TLS Termination](/azure/application-gateway/ssl-overview) and other tasks, simplifying the configuration and maintenance of backend servers. For example, SSL certificates and security policies can be managed at the reverse proxy level instead of on each individual server. ## How a reverse proxy handles HTTP A reverse proxy handles HTTP requests and responses in the following manner: -- Receiving requests: The reverse proxy listens on specified ports and endpoints for incoming HTTP requests from clients. -- Terminating Connections: The inbound HTTP connections are terminated at the proxy and new connections are used for outbound requests to destinations. -- Routing requests: Based on predefined routing rules and configurations, the reverse proxy determines which backend server, or cluster of servers, should handle the request. -- Forwarding requests: The reverse proxy forwards the client request to the appropriate backend server, transforming the path and headers as necessary. -- Connection pooling: The outbound connections are pooled to reduce connection overhead and make most use of HTTP 1.1 reuse and parallel requests with HTTP/2 and HTTP/3. -- Processing responses: The backend server processes the request and sends a response back to the reverse proxy. -- Returning responses: The reverse proxy receives the response from the backend server and forwards it back to the client, performing any necessary response transforms. +* Receiving requests: The reverse proxy listens on specified ports and endpoints for incoming HTTP requests from clients. +* Terminating Connections: The inbound HTTP connections are terminated at the proxy and new connections are used for outbound requests to destinations. +* Routing requests: Based on predefined routing rules and configurations, the reverse proxy determines which backend server, or cluster of servers, should handle the request. +* Forwarding requests: The reverse proxy forwards the client request to the appropriate backend server, transforming the path and headers as necessary. +* Connection pooling: The outbound connections are pooled to reduce connection overhead and make most use of HTTP 1.1 reuse and parallel requests with HTTP/2 and HTTP/3. +* Processing responses: The backend server processes the request and sends a response back to the reverse proxy. +* Returning responses: The reverse proxy receives the response from the backend server and forwards it back to the client, performing any necessary response transforms. This process ensures that the client interacts with the reverse proxy rather than directly with the backend servers, providing the benefits of load balancing, security, versioning, and more. @@ -52,10 +50,10 @@ This process ensures that the client interacts with the reverse proxy rather tha YARP offers several unique benefits that make it an attractive choice for developers: -- Customization: YARP is highly customizable, allowing developers to tailor the proxy to their specific needs with minimal effort. -- Integration with .NET: Built on ASP.NET Core, YARP seamlessly integrates with the .NET ecosystem, making it an ideal choice for .NET developers. -- Extensibility: YARP provides a rich set of extensibility points, enabling developers to add custom logic and features as needed, using familiar C# code. -- Scalability: The direct forwarding extensibility option enables YARP to scale to support domain name and backend scaling that are not viable with most reverse proxies. -- Active development: [YARP is actively maintained](https://github.com/dotnet/yarp) and developed by Microsoft, ensuring it stays up-to-date with the latest technologies and best practices. -- Comprehensive maintained documentation: YARP comes with extensive documentation and examples, making it easy to get started and implement advanced features. -- [Open source](https://github.com/dotnet/yarp). YARP and the YARP documetaion are open source. [Contributions](https://github.com/dotnet/yarp/blob/main/README.md), reviews, and feedback are welcome. +* Customization: YARP is highly customizable, allowing developers to tailor the proxy to their specific needs with minimal effort. +* Integration with .NET: Built on ASP.NET Core, YARP seamlessly integrates with the .NET ecosystem, making it an ideal choice for .NET developers. +* Extensibility: YARP provides a rich set of extensibility points, enabling developers to add custom logic and features as needed, using familiar C# code. +* Scalability: The direct forwarding extensibility option enables YARP to scale to support domain name and backend scaling that are not viable with most reverse proxies. +* Active development: [YARP is actively maintained](https://github.com/dotnet/yarp) and developed by Microsoft, ensuring it stays up-to-date with the latest technologies and best practices. +* Comprehensive maintained documentation: YARP comes with extensive documentation and examples, making it easy to get started and implement advanced features. +* [Open source](https://github.com/dotnet/yarp). YARP and the YARP documentation are open source. [Contributions](https://github.com/dotnet/yarp/blob/main/README.md), reviews, and feedback are welcome. diff --git a/aspnetcore/log-mon/metrics/built-in.md b/aspnetcore/log-mon/metrics/built-in.md new file mode 100644 index 000000000000..c9f4d9433ff0 --- /dev/null +++ b/aspnetcore/log-mon/metrics/built-in.md @@ -0,0 +1,15 @@ +--- +title: ASP.NET Core built-in metrics +description: Built-in metrics for ASP.NET Core apps +author: rick-anderson +ms.author: riande +ms.date: 10/18/2023 +ms.topic: reference +uid: log-mon/metrics/built-in +--- + +# ASP.NET Core built-in metrics + +[!INCLUDE[](~/log-mon/metrics/built-in/includes/built-in10.md)] + +[!INCLUDE[](~/log-mon/metrics/built-in/includes/built-in8.md)] \ No newline at end of file diff --git a/aspnetcore/log-mon/metrics/built-in/includes/built-in10.md b/aspnetcore/log-mon/metrics/built-in/includes/built-in10.md new file mode 100644 index 000000000000..367dc420ff10 --- /dev/null +++ b/aspnetcore/log-mon/metrics/built-in/includes/built-in10.md @@ -0,0 +1,403 @@ +:::moniker range=">= aspnetcore-10.0" + +This article describes the metrics built-in for ASP.NET Core produced using the + API. For a listing of metrics based on the older [EventCounters](/dotnet/core/diagnostics/event-counters) API,see [Available counters](/dotnet/core/diagnostics/available-counters). + +See [Using ASP.NET Core metrics](xref:log-mon/metrics/metrics) for information about how to collect, report, enrich, and test ASP.NET Core metrics + +## `Microsoft.AspNetCore.Hosting` + +The `Microsoft.AspNetCore.Hosting` metrics report high-level information about HTTP requests received by ASP.NET Core: + +- [`http.server.request.duration`](#metric-httpserverrequestduration) +- [`http.server.active_requests`](#metric-httpserveractive_requests) + +#### Metric: `http.server.request.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`http.server.request.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-httpclientrequestduration) | Histogram | `s` | Measures the duration of inbound HTTP requests. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `http.route` | string | The matched route. | `{controller}/{action}/`
`{id?}`| If it's available. | +| `error.type` | string | Describes a class of error the operation ended with. | `timeout`; `name_resolution_error`; `500` | If request has ended with an error. | +| `http.request.method` | string | HTTP request method. | `GET`; `POST`; `HEAD` | Always | +| `http.response.status_code` | int | [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). | `200` | If one was sent. | +| `network.protocol.version` | string | Version of the protocol specified in `network.protocol.name`. | `3.1.1` | Always | +| `url.scheme` | string | The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. | `http`; `https` | Always | +| `aspnetcore.request.is_unhandled` | Boolean | True when the request wasn't handled by the application pipeline. | `true` | If the request was unhandled. | + +The time used to handle an inbound HTTP request as measured at the hosting layer of ASP.NET Core. The time measurement starts once the underlying web host has: + +- Sufficiently parsed the HTTP request headers on the inbound network stream to identify the new request. +- Initialized the context data structures such as the . + +The time ends when: + +- The ASP.NET Core handler pipeline is finished executing. +- All response data has been sent. +- The context data structures for the request are being disposed. + +When using OpenTelemetry, the default buckets for this metric are set to [ 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10 ]. + +#### Metric: `http.server.active_requests` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`http.server.active_requests`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-httpclientactive_requests) | UpDownCounter | `{request}` | Measures the number of concurrent HTTP requests that are currently in-flight. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `http.request.method` | string | HTTP request method. [1] | `GET`; `POST`; `HEAD` | Always | +| `url.scheme`| string | The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. | `http`; `https` | Always | + +. + +## `Microsoft.AspNetCore.Routing` + +The `Microsoft.AspNetCore.Routing` metrics report information about [routing HTTP requests](/aspnet/core/fundamentals/routing) to ASP.NET Core endpoints: + +- [`aspnetcore.routing.match_attempts`](#metric-aspnetcoreroutingmatch_attempts) + +#### Metric: `aspnetcore.routing.match_attempts` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.routing.match_attempts`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcoreroutingmatch_attempts) | Counter | `{match_attempt}` | Number of requests that were attempted to be matched to an endpoint. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.routing.match_status` | string | Match result | `success`; `failure` | Always | +| `aspnetcore.routing.is_fallback_route` | boolean | A value that indicates whether the matched route is a fallback route. | `True` | If a route was successfully matched. | +| `http.route` | string | The matched route | `{controller}/{action}/`
`{id?}` | If a route was successfully matched. | + +. + +## `Microsoft.AspNetCore.Diagnostics` + +The `Microsoft.AspNetCore.Diagnostics` metrics report diagnostics information from [ASP.NET Core error handling middleware](/aspnet/core/fundamentals/error-handling): + +- [`aspnetcore.diagnostics.exceptions`](#metric-aspnetcorediagnosticsexceptions) + +#### Metric: `aspnetcore.diagnostics.exceptions` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.diagnostics.exceptions`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorediagnosticsexceptions) | Counter | `{exception}` | Number of exceptions caught by exception handling middleware. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.diagnostics.exception.result` | string | ASP.NET Core exception middleware handling result | `handled`; `unhandled` | Always | +| `aspnetcore.diagnostics.handler.type` | string | Full type name of the [`IExceptionHandler`](/dotnet/api/microsoft.aspnetcore.diagnostics.iexceptionhandler) implementation that handled the exception. | `Contoso.MyHandler` | If the exception was handled by this handler. | +| `exception.type` | string | The full name of exception type. | `System.OperationCanceledException`; `Contoso.MyException` | Always | + +. + +## `Microsoft.AspNetCore.RateLimiting` + +The `Microsoft.AspNetCore.RateLimiting` metrics report rate limiting information from [ASP.NET Core rate-limiting middleware](/aspnet/core/performance/rate-limit): + +- [`aspnetcore.rate_limiting.active_request_leases`](#metric-aspnetcorerate_limitingactive_request_leases) +- [`aspnetcore.rate_limiting.request_lease.duration`](#metric-aspnetcorerate_limitingrequest_leaseduration) +- [`aspnetcore.rate_limiting.queued_requests`](#metric-aspnetcorerate_limitingqueued_requests) +- [`aspnetcore.rate_limiting.request.time_in_queue`](#metric-aspnetcorerate_limitingrequesttime_in_queue) +- [`aspnetcore.rate_limiting.requests`](#metric-aspnetcorerate_limitingrequests) + +#### Metric: `aspnetcore.rate_limiting.active_request_leases` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.active_request_leases`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingactive_request_leases) | UpDownCounter | `{request}` | Number of requests that are currently active on the server that hold a rate limiting lease. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | + +. + +#### Metric: `aspnetcore.rate_limiting.request_lease.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.request_lease.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingrequest_leaseduration) | Histogram | `s` | The duration of the rate limiting lease held by requests on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | + +. + +#### Metric: `aspnetcore.rate_limiting.queued_requests` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.queued_requests`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingqueued_requests) | UpDownCounter | `{request}` | Number of requests that are currently queued waiting to acquire a rate limiting lease. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | + +. + +#### Metric: `aspnetcore.rate_limiting.request.time_in_queue` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.request.time_in_queue`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingrequesttime_in_queue) | Histogram | `s` | The time a request spent in a queue waiting to acquire a rate limiting lease. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | +| `aspnetcore.rate_limiting.result` | string | The rate limiting result shows whether lease was acquired or contains a rejection reason. | `acquired`; `request_canceled` | Always | + +. + +#### Metric: `aspnetcore.rate_limiting.requests` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.requests`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingrequests) | Counter | `{request}` | Number of requests that tried to acquire a rate limiting lease. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | +| `aspnetcore.rate_limiting.result` | string | The rate limiting result shows whether lease was acquired or contains a rejection reason. | `acquired`; `request_canceled` | Always | + +. + +## `Microsoft.AspNetCore.HeaderParsing` + +The `Microsoft.AspNetCore.HeaderParsing` metrics report information about [ASP.NET Core header parsing](https://www.nuget.org/packages/Microsoft.AspNetCore.HeaderParsing): + +- [`aspnetcore.header_parsing.parse_errors`](#metric-aspnetcoreheader_parsingparse_errors) +- [`aspnetcore.header_parsing.cache_accesses`](#metric-aspnetcoreheader_parsingcache_accesses) + +#### Metric: `aspnetcore.header_parsing.parse_errors` + +| Name | Instrument Type | Unit (UCUM) | Description | +|--|--|--|--| +| `aspnetcore.header_parsing.parse_errors` | Counter | `{parse_error}` | Number of errors that occurred when parsing HTTP request headers. | + +| Attribute | Type | Description | Examples | Presence | +|--|--|--|--|--| +| `aspnetcore.header_parsing.header.name` | string | The header name. | `Content-Type` | Always | +| `error.type` | string | The error message. | `Unable to parse media type value.` | Always | + +. + +#### Metric: `aspnetcore.header_parsing.cache_accesses` + +The metric is emitted only for HTTP request header parsers that support caching. + +| Name | Instrument Type | Unit (UCUM) | Description | +| ---- | --------------- | ----------- | ----------- | +| `aspnetcore.header_parsing.cache_accesses` | Counter | `{cache_access}` | Number of times a cache storing parsed header values was accessed. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.header_parsing.header.name` | string | The header name. | `Content-Type` | Always | +| `aspnetcore.header_parsing.cache_access.type` | string | A value indicating whether the header's value was found in the cache or not. | `Hit`; `Miss` | Always | + +. + +## `Microsoft.AspNetCore.Server.Kestrel` + +The `Microsoft.AspNetCore.Server.Kestrel` metrics report HTTP connection information from [ASP.NET Core Kestrel web server](/aspnet/core/fundamentals/servers/kestrel): + +- [`kestrel.active_connections`](#metric-kestrelactive_connections) +- [`kestrel.connection.duration`](#metric-kestrelconnectionduration) +- [`kestrel.rejected_connections`](#metric-kestrelrejected_connections) +- [`kestrel.queued_connections`](#metric-kestrelqueued_connections) +- [`kestrel.queued_requests`](#metric-kestrelqueued_requests) +- [`kestrel.upgraded_connections`](#metric-kestrelupgraded_connections) +- [`kestrel.tls_handshake.duration`](#metric-kestreltls_handshakeduration) +- [`kestrel.active_tls_handshakes`](#metric-kestrelactive_tls_handshakes) + +#### Metric: `kestrel.active_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.active_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelactive_connections) | UpDownCounter | `{connection}` | Number of connections that are currently active on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type`| string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port`| int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +. + +#### Metric: `kestrel.connection.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.connection.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelconnectionduration) | Histogram | `s` | The duration of connections on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `error.type` | string | Describes a type of error the connection ended with, or the unhandled exception type thrown during the connection pipeline. Known connection errors can be found at [Semantic Conventions for Kestrel web server metrics](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/). | `connection_reset`; `invalid_request_headers`; `System.OperationCanceledException` | If the connection ended with a known error or an exception was thrown. | +| `network.protocol.name` | string | [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. | `http`; `web_sockets` | Always | +| `network.protocol.version` | string | Version of the protocol specified in `network.protocol.name`. | `1.1`; `2` | Always | +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | +| `tls.protocol.version` | string | TLS protocol version. | `1.2`; `1.3` | If the connection is secured with TLS. | + +As this metric is tracking the connection duration, and ideally http connections are used for multiple requests, the buckets should be longer than those used for request durations. For example, using [ 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 120, 300] provides an upper bucket of 5 mins. + +When a connection ends with a known error, the `error.type` attribute value is set to the known error type. Known connection errors can be found at [Semantic Conventions for Kestrel web server metrics](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/). + +#### Metric: `kestrel.rejected_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.rejected_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelrejected_connections) | Counter | `{connection}` | Number of connections rejected by the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport`| string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address`| string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +Connections are rejected when the currently active count exceeds the value configured with `MaxConcurrentConnections`. + +. + +#### Metric: `kestrel.queued_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.queued_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelqueued_connections) | UpDownCounter | `{connection}` | Number of connections that are currently queued and are waiting to start. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +. + +#### Metric: `kestrel.queued_requests` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.queued_requests`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelqueued_requests) | UpDownCounter | `{request}` | Number of HTTP requests on multiplexed connections (HTTP/2 and HTTP/3) that are currently queued and are waiting to start. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.protocol.name` | string | [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. | `http`; `web_sockets` | Always | +| `network.protocol.version` | string | Version of the protocol specified in `network.protocol.name`. | `1.1`; `2` | Always | +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +. + +#### Metric: `kestrel.upgraded_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.upgraded_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelupgraded_connections) | UpDownCounter | `{connection}` | Number of connections that are currently upgraded (WebSockets). | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +The counter only tracks HTTP/1.1 connections. + +. + +#### Metric: `kestrel.tls_handshake.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.tls_handshake.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestreltls_handshakeduration) | Histogram | `s` | The duration of TLS handshakes on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `error.type` | string | The full name of exception type. | `System.OperationCanceledException`; `Contoso.MyException` | If an exception was thrown. | +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | +| `tls.protocol.version` | string | TLS protocol version. | `1.2`; `1.3` | If the connection is secured with TLS. | + +When using OpenTelemetry, the default buckets for this metic are set to [ 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10 ]. + +. + +#### Metric: `kestrel.active_tls_handshakes` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.active_tls_handshakes`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelactive_tls_handshakes) | UpDownCounter | `{handshake}` | Number of TLS handshakes that are currently in progress on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +. + +## `Microsoft.AspNetCore.Http.Connections` + +The `Microsoft.AspNetCore.Http.Connections` metrics report connection information from [ASP.NET Core SignalR](/aspnet/core/signalr/introduction): + +- [`signalr.server.connection.duration`](#metric-signalrserverconnectionduration) +- [`signalr.server.active_connections`](#metric-signalrserveractive_connections) + +#### Metric: `signalr.server.connection.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`signalr.server.connection.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-signalr-metrics/#metric-signalrserverconnectionduration) | Histogram | `s` | The duration of connections on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `signalr.connection.status` | string | SignalR HTTP connection closure status. | `app_shutdown`; `timeout` | Always | +| `signalr.transport` | string | [SignalR transport type](https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/TransportProtocols.md) | `web_sockets`; `long_polling` | Always | + +. + +| Value | Description | +|---|---| +| `normal_closure` | The connection was closed normally. | +| `timeout` | The connection was closed due to a timeout. | +| `app_shutdown` | The connection was closed because the app is shutting down. | + +`signalr.transport` is one of the following: + +| Value | Protocol | +|---|---| +| `server_sent_events` | [server-sent events](https://developer.mozilla.org/docs/Web/API/Server-sent_events/Using_server-sent_events) | +| `long_polling` | [Long Polling](/archive/msdn-magazine/2012/april/cutting-edge-long-polling-and-signalr) | +| `web_sockets` | [WebSocket](https://datatracker.ietf.org/doc/html/rfc6455) | + +As this metric is tracking the connection duration, and ideally SignalR connections are durable, the buckets should be longer than those used for request durations. For example, using [0, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 120, 300] provides an upper bucket of 5 mins. + +. + +#### Metric: `signalr.server.active_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`signalr.server.active_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-signalr-metrics/#metric-signalrserveractive_connections) | UpDownCounter | `{connection}` | Number of connections that are currently active on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `signalr.connection.status` | string | SignalR HTTP connection closure status. | `app_shutdown`; `timeout` | Always | +| `signalr.transport` | string | [SignalR transport type](https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/TransportProtocols.md) | `web_sockets`; `long_polling` | Always | + +. +:::moniker-end diff --git a/aspnetcore/log-mon/metrics/built-in/includes/built-in8.md b/aspnetcore/log-mon/metrics/built-in/includes/built-in8.md new file mode 100644 index 000000000000..70efbbf48fbf --- /dev/null +++ b/aspnetcore/log-mon/metrics/built-in/includes/built-in8.md @@ -0,0 +1,374 @@ +:::moniker range=">= aspnetcore-8.0 < aspnetcore-10.0" + +This article describes the metrics built-in for ASP.NET Core produced using the + API. For a listing of metrics based on the older [EventCounters](/dotnet/core/diagnostics/event-counters) API, +see [Available counters](/dotnet/core/diagnostics/available-counters). + +> [!TIP] +> For more information about how to collect, report, enrich, and test ASP.NET Core metrics, see [Using ASP.NET Core metrics](xref:log-mon/metrics/metrics). + +## `Microsoft.AspNetCore.Hosting` + +The `Microsoft.AspNetCore.Hosting` metrics report high-level information about HTTP requests received by ASP.NET Core: + +- [`http.server.request.duration`](#metric-httpserverrequestduration) +- [`http.server.active_requests`](#metric-httpserveractive_requests) + +##### Metric: `http.server.request.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`http.server.request.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-httpclientrequestduration) | Histogram | `s` | Measures the duration of inbound HTTP requests. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `http.route` | string | The matched route. | `{controller}/{action}/{id?}` | If it's available. | +| `error.type` | string | Describes a class of error the operation ended with. | `timeout`; `name_resolution_error`; `500` | If request has ended with an error. | +| `http.request.method` | string | HTTP request method. | `GET`; `POST`; `HEAD` | Always | +| `http.response.status_code` | int | [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). | `200` | If one was sent. | +| `network.protocol.version` | string | Version of the protocol specified in `network.protocol.name`. | `3.1.1` | Always | +| `url.scheme` | string | The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. | `http`; `https` | Always | +| `aspnetcore.request.is_unhandled` | Boolean | True when the request wasn't handled by the application pipeline. | `true` | If the request was unhandled. | + +The time used to handle an inbound HTTP request as measured at the hosting layer of ASP.NET Core. The time measurement starts once the underlying web host has: + +- Sufficiently parsed the HTTP request headers on the inbound network stream to identify the new request. +- Initialized the context data structures such as the . + +The time ends when: + +- The ASP.NET Core handler pipeline is finished executing. +- All response data has been sent. +- The context data structures for the request are being disposed. + +When using OpenTelemetry, the default buckets for this metric are set to [ 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10 ]. + +##### Metric: `http.server.active_requests` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`http.server.active_requests`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-httpclientactive_requests) | UpDownCounter | `{request}` | Measures the number of concurrent HTTP requests that are currently in-flight. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `http.request.method` | string | HTTP request method. [1] | `GET`; `POST`; `HEAD` | Always | +| `url.scheme`| string | The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. | `http`; `https` | Always | + +## `Microsoft.AspNetCore.Routing` + +The `Microsoft.AspNetCore.Routing` metrics report information about [routing HTTP requests](/aspnet/core/fundamentals/routing) to ASP.NET Core endpoints: + +- [`aspnetcore.routing.match_attempts`](#metric-aspnetcoreroutingmatch_attempts) + +##### Metric: `aspnetcore.routing.match_attempts` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.routing.match_attempts`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcoreroutingmatch_attempts) | Counter | `{match_attempt}` | Number of requests that were attempted to be matched to an endpoint. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.routing.match_status` | string | Match result | `success`; `failure` | Always | +| `aspnetcore.routing.is_fallback_route` | boolean | A value that indicates whether the matched route is a fallback route. | `True` | If a route was successfully matched. | +| `http.route` | string | The matched route | `{controller}/{action}/{id?}` | If a route was successfully matched. | + +## `Microsoft.AspNetCore.Diagnostics` + +The `Microsoft.AspNetCore.Diagnostics` metrics report diagnostics information from [ASP.NET Core error handling middleware](/aspnet/core/fundamentals/error-handling): + +- [`aspnetcore.diagnostics.exceptions`](#metric-aspnetcorediagnosticsexceptions) + +##### Metric: `aspnetcore.diagnostics.exceptions` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.diagnostics.exceptions`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorediagnosticsexceptions) | Counter | `{exception}` | Number of exceptions caught by exception handling middleware. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.diagnostics.exception.result` | string | ASP.NET Core exception middleware handling result | `handled`; `unhandled` | Always | +| `aspnetcore.diagnostics.handler.type` | string | Full type name of the [`IExceptionHandler`](/dotnet/api/microsoft.aspnetcore.diagnostics.iexceptionhandler) implementation that handled the exception. | `Contoso.MyHandler` | If the exception was handled by this handler. | +| `exception.type` | string | The full name of exception type. | `System.OperationCanceledException`; `Contoso.MyException` | Always | + +## `Microsoft.AspNetCore.RateLimiting` + +The `Microsoft.AspNetCore.RateLimiting` metrics report rate limiting information from [ASP.NET Core rate-limiting middleware](/aspnet/core/performance/rate-limit): + +- [`aspnetcore.rate_limiting.active_request_leases`](#metric-aspnetcorerate_limitingactive_request_leases) +- [`aspnetcore.rate_limiting.request_lease.duration`](#metric-aspnetcorerate_limitingrequest_leaseduration) +- [`aspnetcore.rate_limiting.queued_requests`](#metric-aspnetcorerate_limitingqueued_requests) +- [`aspnetcore.rate_limiting.request.time_in_queue`](#metric-aspnetcorerate_limitingrequesttime_in_queue) +- [`aspnetcore.rate_limiting.requests`](#metric-aspnetcorerate_limitingrequests) + +##### Metric: `aspnetcore.rate_limiting.active_request_leases` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.active_request_leases`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingactive_request_leases) | UpDownCounter | `{request}` | Number of requests that are currently active on the server that hold a rate limiting lease. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | + +##### Metric: `aspnetcore.rate_limiting.request_lease.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.request_lease.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingrequest_leaseduration) | Histogram | `s` | The duration of the rate limiting lease held by requests on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | + +##### Metric: `aspnetcore.rate_limiting.queued_requests` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.queued_requests`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingqueued_requests) | UpDownCounter | `{request}` | Number of requests that are currently queued waiting to acquire a rate limiting lease. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | + +##### Metric: `aspnetcore.rate_limiting.request.time_in_queue` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.request.time_in_queue`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingrequesttime_in_queue) | Histogram | `s` | The time a request spent in a queue waiting to acquire a rate limiting lease. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | +| `aspnetcore.rate_limiting.result` | string | The rate limiting result shows whether lease was acquired or contains a rejection reason. | `acquired`; `request_canceled` | Always | + +##### Metric: `aspnetcore.rate_limiting.requests` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`aspnetcore.rate_limiting.requests`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-aspnetcore-metrics/#metric-aspnetcorerate_limitingrequests) | Counter | `{request}` | Number of requests that tried to acquire a rate limiting lease. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.rate_limiting.policy` | string | Rate limiting policy name. | `fixed`; `sliding`; `token` | If the matched endpoint for the request had a rate-limiting policy. | +| `aspnetcore.rate_limiting.result` | string | The rate limiting result shows whether lease was acquired or contains a rejection reason. | `acquired`; `request_canceled` | Always | + +## `Microsoft.AspNetCore.HeaderParsing` + +The `Microsoft.AspNetCore.HeaderParsing` metrics report information about [ASP.NET Core header parsing](https://www.nuget.org/packages/Microsoft.AspNetCore.HeaderParsing): + +- [`aspnetcore.header_parsing.parse_errors`](#metric-aspnetcoreheader_parsingparse_errors) +- [`aspnetcore.header_parsing.cache_accesses`](#metric-aspnetcoreheader_parsingcache_accesses) + +##### Metric: `aspnetcore.header_parsing.parse_errors` + +| Name | Instrument Type | Unit (UCUM) | Description | +|--|--|--|--| +| `aspnetcore.header_parsing.parse_errors` | Counter | `{parse_error}` | Number of errors that occurred when parsing HTTP request headers. | + +| Attribute | Type | Description | Examples | Presence | +|--|--|--|--|--| +| `aspnetcore.header_parsing.header.name` | string | The header name. | `Content-Type` | Always | +| `error.type` | string | The error message. | `Unable to parse media type value.` | Always | + +##### Metric: `aspnetcore.header_parsing.cache_accesses` + +The metric is emitted only for HTTP request header parsers that support caching. + +| Name | Instrument Type | Unit (UCUM) | Description | +| ---- | --------------- | ----------- | ----------- | +| `aspnetcore.header_parsing.cache_accesses` | Counter | `{cache_access}` | Number of times a cache storing parsed header values was accessed. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `aspnetcore.header_parsing.header.name` | string | The header name. | `Content-Type` | Always | +| `aspnetcore.header_parsing.cache_access.type` | string | A value indicating whether the header's value was found in the cache or not. | `Hit`; `Miss` | Always | + +## `Microsoft.AspNetCore.Server.Kestrel` + +The `Microsoft.AspNetCore.Server.Kestrel` metrics report HTTP connection information from [ASP.NET Core Kestrel web server](/aspnet/core/fundamentals/servers/kestrel): + +- [`kestrel.active_connections`](#metric-kestrelactive_connections) +- [`kestrel.connection.duration`](#metric-kestrelconnectionduration) +- [`kestrel.rejected_connections`](#metric-kestrelrejected_connections) +- [`kestrel.queued_connections`](#metric-kestrelqueued_connections) +- [`kestrel.queued_requests`](#metric-kestrelqueued_requests) +- [`kestrel.upgraded_connections`](#metric-kestrelupgraded_connections) +- [`kestrel.tls_handshake.duration`](#metric-kestreltls_handshakeduration) +- [`kestrel.active_tls_handshakes`](#metric-kestrelactive_tls_handshakes) + +##### Metric: `kestrel.active_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.active_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelactive_connections) | UpDownCounter | `{connection}` | Number of connections that are currently active on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type`| string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port`| int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +##### Metric: `kestrel.connection.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.connection.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelconnectionduration) | Histogram | `s` | The duration of connections on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `error.type` | string | Describes a type of error the connection ended with, or the unhandled exception type thrown during the connection pipeline. Known connection errors can be found at [Semantic Conventions for Kestrel web server metrics](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/). | `connection_reset`; `invalid_request_headers`; `System.OperationCanceledException` | If the connection ended with a known error or an exception was thrown. | +| `network.protocol.name` | string | [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. | `http`; `web_sockets` | Always | +| `network.protocol.version` | string | Version of the protocol specified in `network.protocol.name`. | `1.1`; `2` | Always | +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | +| `tls.protocol.version` | string | TLS protocol version. | `1.2`; `1.3` | If the connection is secured with TLS. | + +As this metric is tracking the connection duration, and ideally http connections are used for multiple requests, the buckets should be longer than those used for request durations. For example, using [ 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 120, 300] provides an upper bucket of 5 mins. + +:::moniker-end + +:::moniker range="= aspnetcore-9.0" + +When a connection ends with a known error, the `error.type` attribute value is set to the known error type. Known connection errors can be found at [Semantic Conventions for Kestrel web server metrics](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/). + +:::moniker-end + +:::moniker range=">= aspnetcore-8.0 < aspnetcore-10.0" + +##### Metric: `kestrel.rejected_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.rejected_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelrejected_connections) | Counter | `{connection}` | Number of connections rejected by the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport`| string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address`| string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +Connections are rejected when the currently active count exceeds the value configured with `MaxConcurrentConnections`. + +##### Metric: `kestrel.queued_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.queued_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelqueued_connections) | UpDownCounter | `{connection}` | Number of connections that are currently queued and are waiting to start. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +##### Metric: `kestrel.queued_requests` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.queued_requests`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelqueued_requests) | UpDownCounter | `{request}` | Number of HTTP requests on multiplexed connections (HTTP/2 and HTTP/3) that are currently queued and are waiting to start. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.protocol.name` | string | [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. | `http`; `web_sockets` | Always | +| `network.protocol.version` | string | Version of the protocol specified in `network.protocol.name`. | `1.1`; `2` | Always | +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +##### Metric: `kestrel.upgraded_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.upgraded_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelupgraded_connections) | UpDownCounter | `{connection}` | Number of connections that are currently upgraded (WebSockets). | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +The counter only tracks HTTP/1.1 connections. + +##### Metric: `kestrel.tls_handshake.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.tls_handshake.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestreltls_handshakeduration) | Histogram | `s` | The duration of TLS handshakes on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `error.type` | string | The full name of exception type. | `System.OperationCanceledException`; `Contoso.MyException` | If an exception was thrown. | +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | +| `tls.protocol.version` | string | TLS protocol version. | `1.2`; `1.3` | If the connection is secured with TLS. | + +When using OpenTelemetry, the default buckets for this metic are set to [ 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10 ]. + +##### Metric: `kestrel.active_tls_handshakes` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`kestrel.active_tls_handshakes`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-kestrel-metrics/#metric-kestrelactive_tls_handshakes) | UpDownCounter | `{handshake}` | Number of TLS handshakes that are currently in progress on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `network.transport` | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://en.wikipedia.org/wiki/Inter-process_communication). | `tcp`; `unix` | Always | +| `network.type` | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. | `ipv4`; `ipv6` | If the transport is `tcp` or `udp`. | +| `server.address` | string | Server address domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. | `example.com` | Always | +| `server.port` | int | Server port number | `80`; `8080`; `443` | If the transport is `tcp` or `udp`. | + +## `Microsoft.AspNetCore.Http.Connections` + +The `Microsoft.AspNetCore.Http.Connections` metrics report connection information from [ASP.NET Core SignalR](/aspnet/core/signalr/introduction): + +- [`signalr.server.connection.duration`](#metric-signalrserverconnectionduration) +- [`signalr.server.active_connections`](#metric-signalrserveractive_connections) + +##### Metric: `signalr.server.connection.duration` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`signalr.server.connection.duration`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-signalr-metrics/#metric-signalrserverconnectionduration) | Histogram | `s` | The duration of connections on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `signalr.connection.status` | string | SignalR HTTP connection closure status. | `app_shutdown`; `timeout` | Always | +| `signalr.transport` | string | [SignalR transport type](https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/TransportProtocols.md) | `web_sockets`; `long_polling` | Always | + +| Value | Description | +|---|---| +| `normal_closure` | The connection was closed normally. | +| `timeout` | The connection was closed due to a timeout. | +| `app_shutdown` | The connection was closed because the app is shutting down. | + +`signalr.transport` is one of the following: + +| Value | Protocol | +|---|---| +| `server_sent_events` | [server-sent events](https://developer.mozilla.org/docs/Web/API/Server-sent_events/Using_server-sent_events) | +| `long_polling` | [Long Polling](/archive/msdn-magazine/2012/april/cutting-edge-long-polling-and-signalr) | +| `web_sockets` | [WebSocket](https://datatracker.ietf.org/doc/html/rfc6455) | + +As this metric is tracking the connection duration, and ideally SignalR connections are durable, the buckets should be longer than those used for request durations. For example, using [0, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 120, 300] provides an upper bucket of 5 mins. + +##### Metric: `signalr.server.active_connections` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| [`signalr.server.active_connections`](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-signalr-metrics/#metric-signalrserveractive_connections) | UpDownCounter | `{connection}` | Number of connections that are currently active on the server. | + +| Attribute | Type | Description | Examples | Presence | +|---|---|---|---|---| +| `signalr.connection.status` | string | SignalR HTTP connection closure status. | `app_shutdown`; `timeout` | Always | +| `signalr.transport` | string | [SignalR transport type](https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/TransportProtocols.md) | `web_sockets`; `long_polling` | Always | + +:::moniker-end diff --git a/aspnetcore/security/authentication/configure-oidc-web-authentication.md b/aspnetcore/security/authentication/configure-oidc-web-authentication.md index acf88217a096..1f5551fe4a56 100644 --- a/aspnetcore/security/authentication/configure-oidc-web-authentication.md +++ b/aspnetcore/security/authentication/configure-oidc-web-authentication.md @@ -101,7 +101,7 @@ For the different claims mapping possibilities, see . +Add the OpenID Connect client settings to the application configuration properties. The settings must match the client configuration in the OpenID Connect server. No secrets should be persisted in application settings where they might get accidentally checked in. Secrets should be stored in a secure location like Azure Key Vault in production environments or in user secrets in a development environment. For more information, see . ```json "OpenIDConnectSettings": { diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index b6cd57e2e6ba..31380cc7316a 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -287,8 +287,8 @@ items: - name: Metrics overview displayName: logging, monitoring uid: log-mon/metrics/metrics - - name: Built-in metrics >> - href: /dotnet/core/diagnostics/built-in-metrics-aspnetcore + - name: Built-in metrics + uid: log-mon/metrics/built-in - name: HttpContext uid: fundamentals/use-httpcontext - name: Routing