Make HttpContext available to OpenAPI transformers
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 281
Description
## Background and Motivation
I was looking at how to wire up the `servers` property based on the current HttpContext [like NSwag does](https://github.com/RicoSuter/NSwag/blob/6b49eefa4048cecfd41ba0d7484bd1f25543d22d/src/NSwag.AspNetCore/Middlewares/OpenApiDocumentMiddleware.cs#L144-L147) after opening #56188, and noticed that the `HttpContext` isn't immediately available to any OpenAPI transformers.
It can be easily be made available via `IHttpContextAccessor`, but that's often frowned upon from a performance perspective, so I figured it would be worth raising the possibility of making it available from the request pipeline to avoid the need to do that.
The `HttpContext` could be passed through into `OpenApiDocumentService.GetOpenApiDocumentAsync()` here:
https://github.com/dotnet/aspnetcore/blob/2b5d2b36a04f3a4a9bb20bbca38617d1cd6a3a1a/src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs#L46
Then it can be directly assigned into the various context objects passed to any transformers, as well as being available to the document service itself.
## Proposed API
```diff
namespace Microsoft.AspNetCore.OpenApi;
public sealed partial class OpenApiDocumentTransformerContext
{
+ ///
+ /// Gets the HTTP context associated with the current HTTP request.
+ ///
+ public required HttpContext { get; init }
}
public sealed partial class OpenApiOperationTransformerContext
{
+ ///
+ /// Gets the HTTP context associated with the current HTTP request.
+ ///
+ public required HttpContext { get; init }
}
public sealed partial class OpenApiSchemaTransformerContext
{
+ ///
+ /// Gets the HTTP context associated with the current HTTP request.
+ ///
+ public required HttpContext { get; init }
}
```
## Usage Examples
```csharp
internal sealed class AddServersTransformer : IOpenApiDocumentTransformer
{
///
public Task TransformAsync(
OpenApiDocument document,
OpenApiDocumentTransformerContext context,
CancellationToken cancellationToken)
{
document.Servers = [new() { Url = GetServerUrl(context) }];
return Task.CompletedTask;
}
private static string GetServerUrl(OpenApiDocumentTransformerContext context)
{
var request = context.HttpContext.Request;
var scheme = TryGetFirstHeader("X-Forwarded-Proto") ?? request.Scheme;
var host = TryGetFirstHeader("X-Forwarded-Host") ?? request.Host.ToString();
return new Uri($"{scheme}://{host}").ToString().TrimEnd('/');
string? TryGetFirstHeader(string name)
=> request.Headers.TryGetValue(name, out var values) ? values.FirstOrDefault() : null;
}
}
```
## Alternative Designs
None.
## Risks
None?
Contributor guide
Assessment
This issue has not been assessed yet.