Closed
Description
When adding a route handler filter via a filter factory there are cases where the filter factory (as opposed to the filter itself) needs access to the application services, e.g. to get an ILogger
instance. We should add a property to RouteHandlerContext
to enable this.
namespace Microsoft.AspNetCore.Http;
public sealed class RouteHandlerContext
{
+ public IServiceProvider ApplicationServices { get; }
}
Note that the property is nullable due to where it's instantiated in RequestDelegateFactory
and matches the Services
properties on EndpointMetadataContext
and EndpointParameterMetadataContext
.
Example Usage
public static RouteHandlerBuilder WithParameterValidation(this RouteHandlerBuilder builder, int statusCode = StatusCodes.Status400BadRequest)
{
builder.Add(eb =>
{
var methodInfo = eb.Metadata.OfType<MethodInfo>().SingleOrDefault();
if (methodInfo is not null && IsValidatable(methodInfo))
{
eb.Metadata.Add(new ProducesResponseTypeAttribute(typeof(HttpValidationProblemDetails), statusCode, "application/problem+json"));
}
});
builder.AddFilter((RouteHandlerContext context, RouteHandlerFilterDelegate next) =>
{
// *************************************
// ** We use ApplicationServices here **
// *************************************
var loggerFactory = context.ApplicationServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.Create("MinimalApis.Extensions.Filters.ValidationRouteHandlerFilterFactory");
if (!IsValidatable(context.MethodInfo))
{
return next;
}
return rhic =>
{
foreach (var parameter in rhic.Parameters)
{
if (parameter is not null && !MiniValidator.TryValidate(parameter, out var errors))
{
return new(Results.ValidationProblem(errors));
}
}
return next(rhic);
};
});
return builder;
}
Risks
Should be very low. This is following the pattern used in other context classes including those where the call site originates in RequestDelegateFactory
, e.g. EndpointMetadataContext
.