diff --git a/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt b/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt index 338549737153..c940f762c584 100644 --- a/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt @@ -169,9 +169,9 @@ static Microsoft.AspNetCore.Http.HeaderDictionaryTypeExtensions.AppendList(th static Microsoft.AspNetCore.Http.HeaderDictionaryTypeExtensions.GetTypedHeaders(this Microsoft.AspNetCore.Http.HttpRequest! request) -> Microsoft.AspNetCore.Http.Headers.RequestHeaders! static Microsoft.AspNetCore.Http.HeaderDictionaryTypeExtensions.GetTypedHeaders(this Microsoft.AspNetCore.Http.HttpResponse! response) -> Microsoft.AspNetCore.Http.Headers.ResponseHeaders! static Microsoft.AspNetCore.Http.HttpContextServerVariableExtensions.GetServerVariable(this Microsoft.AspNetCore.Http.HttpContext! context, string! variableName) -> string? -static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Delegate! action) -> Microsoft.AspNetCore.Http.RequestDelegate! -static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo) -> Microsoft.AspNetCore.Http.RequestDelegate! -static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo, System.Func! targetFactory) -> Microsoft.AspNetCore.Http.RequestDelegate! +static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Delegate! action, System.IServiceProvider? serviceProvider) -> Microsoft.AspNetCore.Http.RequestDelegate! +static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo, System.IServiceProvider? serviceProvider) -> Microsoft.AspNetCore.Http.RequestDelegate! +static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo, System.IServiceProvider? serviceProvider, System.Func! targetFactory) -> Microsoft.AspNetCore.Http.RequestDelegate! static Microsoft.AspNetCore.Http.ResponseExtensions.Clear(this Microsoft.AspNetCore.Http.HttpResponse! response) -> void static Microsoft.AspNetCore.Http.ResponseExtensions.Redirect(this Microsoft.AspNetCore.Http.HttpResponse! response, string! location, bool permanent, bool preserveMethod) -> void static Microsoft.AspNetCore.Http.SendFileResponseExtensions.SendFileAsync(this Microsoft.AspNetCore.Http.HttpResponse! response, Microsoft.Extensions.FileProviders.IFileInfo! file, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index 6232a5479a00..b14ef5fb3d40 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -62,8 +62,9 @@ public static class RequestDelegateFactory /// Creates a implementation for . /// /// A request handler with any number of custom parameters that often produces a response with its return value. + /// The instance used to detect which parameters are services. /// The . - public static RequestDelegate Create(Delegate action) + public static RequestDelegate Create(Delegate action, IServiceProvider? serviceProvider) { if (action is null) { @@ -76,7 +77,7 @@ public static RequestDelegate Create(Delegate action) null => null, }; - var targetableRequestDelegate = CreateTargetableRequestDelegate(action.Method, targetExpression); + var targetableRequestDelegate = CreateTargetableRequestDelegate(action.Method, serviceProvider, targetExpression); return httpContext => { @@ -88,15 +89,16 @@ public static RequestDelegate Create(Delegate action) /// Creates a implementation for . /// /// A static request handler with any number of custom parameters that often produces a response with its return value. + /// The instance used to detect which parameters are services. /// The . - public static RequestDelegate Create(MethodInfo methodInfo) + public static RequestDelegate Create(MethodInfo methodInfo, IServiceProvider? serviceProvider) { if (methodInfo is null) { throw new ArgumentNullException(nameof(methodInfo)); } - var targetableRequestDelegate = CreateTargetableRequestDelegate(methodInfo, targetExpression: null); + var targetableRequestDelegate = CreateTargetableRequestDelegate(methodInfo, serviceProvider, targetExpression: null); return httpContext => { @@ -108,9 +110,10 @@ public static RequestDelegate Create(MethodInfo methodInfo) /// Creates a implementation for . /// /// A request handler with any number of custom parameters that often produces a response with its return value. + /// The instance used to detect which parameters are services. /// Creates the for the non-static method. /// The . - public static RequestDelegate Create(MethodInfo methodInfo, Func targetFactory) + public static RequestDelegate Create(MethodInfo methodInfo, IServiceProvider? serviceProvider, Func targetFactory) { if (methodInfo is null) { @@ -128,7 +131,7 @@ public static RequestDelegate Create(MethodInfo methodInfo, Func { @@ -136,7 +139,7 @@ public static RequestDelegate Create(MethodInfo methodInfo, Func CreateTargetableRequestDelegate(MethodInfo methodInfo, Expression? targetExpression) + private static Func CreateTargetableRequestDelegate(MethodInfo methodInfo, IServiceProvider? serviceProvider, Expression? targetExpression) { // Non void return type @@ -154,7 +157,10 @@ public static RequestDelegate Create(MethodInfo methodInfo, Func() is IServiceProviderIsService serviceProviderIsService) + { + // If the parameter resolves as a service then get it from services + if (serviceProviderIsService.IsService(parameter.ParameterType)) + { + return Expression.Call(GetRequiredServiceMethod.MakeGenericMethod(parameter.ParameterType), RequestServicesExpr); + } + } + return BindParameterFromBody(parameter.ParameterType, allowEmpty: false, factoryContext); } } @@ -788,6 +803,7 @@ private class FactoryContext { public Type? JsonRequestBodyType { get; set; } public bool AllowEmptyRequestBody { get; set; } + public IServiceProvider? ServiceProvider { get; init; } public bool UsingTempSourceString { get; set; } public List<(ParameterExpression, Expression)> TryParseParams { get; } = new(); diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs index ae85b27e3ee3..bac3c83201dd 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs @@ -92,7 +92,7 @@ public async Task RequestDelegateInvokesAction(Delegate @delegate) { var httpContext = new DefaultHttpContext(); - var requestDelegate = RequestDelegateFactory.Create(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -112,7 +112,7 @@ public async Task StaticMethodInfoOverloadWorksWithBasicReflection() BindingFlags.NonPublic | BindingFlags.Static, new[] { typeof(HttpContext) }); - var requestDelegate = RequestDelegateFactory.Create(methodInfo!); + var requestDelegate = RequestDelegateFactory.Create(methodInfo!, new EmptyServiceProvdier()); var httpContext = new DefaultHttpContext(); @@ -158,7 +158,7 @@ object GetTarget() return new TestNonStaticActionClass(2); } - var requestDelegate = RequestDelegateFactory.Create(methodInfo!, _ => GetTarget()); + var requestDelegate = RequestDelegateFactory.Create(methodInfo!, new EmptyServiceProvdier(), _ => GetTarget()); var httpContext = new DefaultHttpContext(); @@ -181,10 +181,12 @@ public void BuildRequestDelegateThrowsArgumentNullExceptions() BindingFlags.NonPublic | BindingFlags.Static, new[] { typeof(HttpContext) }); - var exNullAction = Assert.Throws(() => RequestDelegateFactory.Create(action: null!)); - var exNullMethodInfo1 = Assert.Throws(() => RequestDelegateFactory.Create(methodInfo: null!)); - var exNullMethodInfo2 = Assert.Throws(() => RequestDelegateFactory.Create(methodInfo: null!, _ => 0)); - var exNullTargetFactory = Assert.Throws(() => RequestDelegateFactory.Create(methodInfo!, targetFactory: null!)); + var serviceProvider = new EmptyServiceProvdier(); + + var exNullAction = Assert.Throws(() => RequestDelegateFactory.Create(action: null!, serviceProvider)); + var exNullMethodInfo1 = Assert.Throws(() => RequestDelegateFactory.Create(methodInfo: null!, serviceProvider)); + var exNullMethodInfo2 = Assert.Throws(() => RequestDelegateFactory.Create(methodInfo: null!, serviceProvider, _ => 0)); + var exNullTargetFactory = Assert.Throws(() => RequestDelegateFactory.Create(methodInfo!, serviceProvider, targetFactory: null!)); Assert.Equal("action", exNullAction.ParamName); Assert.Equal("methodInfo", exNullMethodInfo1.ParamName); @@ -206,7 +208,7 @@ void TestAction(HttpContext httpContext, [FromRoute] int value) var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues[paramName] = originalRouteParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -233,7 +235,7 @@ public async Task RequestDelegatePopulatesFromRouteOptionalParameter() { var httpContext = new DefaultHttpContext(); - var requestDelegate = RequestDelegateFactory.Create((Action)TestOptional); + var requestDelegate = RequestDelegateFactory.Create((Action)TestOptional, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -245,7 +247,7 @@ public async Task RequestDelegatePopulatesFromNullableOptionalParameter() { var httpContext = new DefaultHttpContext(); - var requestDelegate = RequestDelegateFactory.Create((Action)TestOptional); + var requestDelegate = RequestDelegateFactory.Create((Action)TestOptional, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -257,7 +259,7 @@ public async Task RequestDelegatePopulatesFromOptionalStringParameter() { var httpContext = new DefaultHttpContext(); - var requestDelegate = RequestDelegateFactory.Create((Action)TestOptionalString); + var requestDelegate = RequestDelegateFactory.Create((Action)TestOptionalString, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -274,7 +276,7 @@ public async Task RequestDelegatePopulatesFromRouteOptionalParameterBasedOnParam httpContext.Request.RouteValues[paramName] = originalRouteParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = RequestDelegateFactory.Create((Action)TestOptional); + var requestDelegate = RequestDelegateFactory.Create((Action)TestOptional, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -297,7 +299,7 @@ void TestAction([FromRoute(Name = specifiedName)] int foo) var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues[specifiedName] = originalRouteParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -320,7 +322,7 @@ void TestAction([FromRoute] int foo) var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues[unmatchedName] = unmatchedRouteParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -399,7 +401,7 @@ public async Task RequestDelegatePopulatesUnattributedTryParsableParametersFromR var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues["tryParsable"] = routeValue; - var requestDelegate = RequestDelegateFactory.Create(action); + var requestDelegate = RequestDelegateFactory.Create(action, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -416,7 +418,7 @@ public async Task RequestDelegatePopulatesUnattributedTryParsableParametersFromQ ["tryParsable"] = routeValue }); - var requestDelegate = RequestDelegateFactory.Create(action); + var requestDelegate = RequestDelegateFactory.Create(action, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -437,8 +439,9 @@ public async Task RequestDelegatePopulatesUnattributedTryParsableParametersFromR var requestDelegate = RequestDelegateFactory.Create((Action)((httpContext, tryParsable) => { - httpContext.Items["tryParsable"] = tryParsable; - })); + httpContext.Items["tryParsable"] = tryParsable; + }), + new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -466,7 +469,7 @@ public static object[][] DelegatesWithAttributesOnNotTryParsableParameters [MemberData(nameof(DelegatesWithAttributesOnNotTryParsableParameters))] public void CreateThrowsInvalidOperationExceptionWhenAttributeRequiresTryParseMethodThatDoesNotExist(Delegate action) { - var ex = Assert.Throws(() => RequestDelegateFactory.Create(action)); + var ex = Assert.Throws(() => RequestDelegateFactory.Create(action, new EmptyServiceProvdier())); Assert.Equal("No public static bool Object.TryParse(string, out Object) method found for notTryParsable.", ex.Message); } @@ -475,7 +478,7 @@ public void CreateThrowsInvalidOperationExceptionGivenUnnamedArgument() { var unnamedParameter = Expression.Parameter(typeof(int)); var lambda = Expression.Lambda(Expression.Block(), unnamedParameter); - var ex = Assert.Throws(() => RequestDelegateFactory.Create((Action)lambda.Compile())); + var ex = Assert.Throws(() => RequestDelegateFactory.Create((Action)lambda.Compile(), new EmptyServiceProvdier())); Assert.Equal("A parameter does not have a name! Was it genererated? All parameters must be named.", ex.Message); } @@ -498,7 +501,7 @@ void TestAction([FromRoute] int tryParsable, [FromRoute] int tryParsable2) httpContext.Features.Set(new TestHttpRequestLifetimeFeature()); httpContext.RequestServices = serviceCollection.BuildServiceProvider(); - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -540,7 +543,7 @@ void TestAction([FromQuery] int value) var httpContext = new DefaultHttpContext(); httpContext.Request.Query = query; - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -563,7 +566,7 @@ void TestAction([FromHeader(Name = customHeaderName)] int value) var httpContext = new DefaultHttpContext(); httpContext.Request.Headers[customHeaderName] = originalHeaderParam.ToString(NumberFormatInfo.InvariantInfo); - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -607,7 +610,7 @@ public async Task RequestDelegatePopulatesFromBodyParameter(Delegate action) var requestBodyBytes = JsonSerializer.SerializeToUtf8Bytes(originalTodo); httpContext.Request.Body = new MemoryStream(requestBodyBytes); - var requestDelegate = RequestDelegateFactory.Create(action); + var requestDelegate = RequestDelegateFactory.Create(action, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -624,7 +627,7 @@ public async Task RequestDelegateRejectsEmptyBodyGivenFromBodyParameter(Delegate httpContext.Request.Headers["Content-Type"] = "application/json"; httpContext.Request.Headers["Content-Length"] = "0"; - var requestDelegate = RequestDelegateFactory.Create(action); + var requestDelegate = RequestDelegateFactory.Create(action, new EmptyServiceProvdier()); await Assert.ThrowsAsync(() => requestDelegate(httpContext)); } @@ -643,7 +646,7 @@ void TestAction([FromBody(AllowEmpty = true)] Todo todo) httpContext.Request.Headers["Content-Type"] = "application/json"; httpContext.Request.Headers["Content-Length"] = "0"; - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -667,7 +670,7 @@ void TestAction([FromBody(AllowEmpty = true)] BodyStruct bodyStruct) httpContext.Request.Headers["Content-Type"] = "application/json"; httpContext.Request.Headers["Content-Length"] = "0"; - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -694,7 +697,7 @@ void TestAction([FromBody] Todo todo) httpContext.Features.Set(new TestHttpRequestLifetimeFeature()); httpContext.RequestServices = serviceCollection.BuildServiceProvider(); - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -727,7 +730,7 @@ void TestAction([FromBody] Todo todo) httpContext.Features.Set(new TestHttpRequestLifetimeFeature()); httpContext.RequestServices = serviceCollection.BuildServiceProvider(); - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -748,9 +751,9 @@ public void BuildRequestDelegateThrowsInvalidOperationExceptionGivenFromBodyOnMu void TestInferredInvalidAction(Todo value1, Todo value2) { } void TestBothInvalidAction(Todo value1, [FromBody] int value2) { } - Assert.Throws(() => RequestDelegateFactory.Create((Action)TestAttributedInvalidAction)); - Assert.Throws(() => RequestDelegateFactory.Create((Action)TestInferredInvalidAction)); - Assert.Throws(() => RequestDelegateFactory.Create((Action)TestBothInvalidAction)); + Assert.Throws(() => RequestDelegateFactory.Create((Action)TestAttributedInvalidAction, new EmptyServiceProvdier())); + Assert.Throws(() => RequestDelegateFactory.Create((Action)TestInferredInvalidAction, new EmptyServiceProvdier())); + Assert.Throws(() => RequestDelegateFactory.Create((Action)TestBothInvalidAction, new EmptyServiceProvdier())); } public static object[][] FromServiceActions @@ -777,12 +780,18 @@ void TestImpliedIEnumerableFromService(HttpContext httpContext, IEnumerable)TestExplicitFromService }, new[] { (Action>)TestExplicitFromIEnumerableService }, new[] { (Action)TestImpliedFromService }, new[] { (Action>)TestImpliedIEnumerableFromService }, + new[] { (Action)TestImpliedFromServiceBasedOnContainer }, }; } } @@ -797,10 +806,14 @@ public async Task RequestDelegatePopulatesParametersFromServiceWithAndWithoutAtt serviceCollection.AddSingleton(myOriginalService); serviceCollection.AddSingleton(myOriginalService); + var services = serviceCollection.BuildServiceProvider(); + + using var requestScoped = services.CreateScope(); + var httpContext = new DefaultHttpContext(); - httpContext.RequestServices = serviceCollection.BuildServiceProvider(); + httpContext.RequestServices = requestScoped.ServiceProvider; - var requestDelegate = RequestDelegateFactory.Create(action); + var requestDelegate = RequestDelegateFactory.Create(action, services); await requestDelegate(httpContext); @@ -812,9 +825,9 @@ public async Task RequestDelegatePopulatesParametersFromServiceWithAndWithoutAtt public async Task RequestDelegateRequiresServiceForAllFromServiceParameters(Delegate action) { var httpContext = new DefaultHttpContext(); - httpContext.RequestServices = new ServiceCollection().BuildServiceProvider(); + httpContext.RequestServices = new EmptyServiceProvdier(); - var requestDelegate = RequestDelegateFactory.Create(action); + var requestDelegate = RequestDelegateFactory.Create(action, new EmptyServiceProvdier()); await Assert.ThrowsAsync(() => requestDelegate(httpContext)); } @@ -831,7 +844,7 @@ void TestAction(HttpContext httpContext) var httpContext = new DefaultHttpContext(); - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -854,7 +867,7 @@ void TestAction(CancellationToken cancellationToken) RequestAborted = cts.Token }; - var requestDelegate = RequestDelegateFactory.Create((Action)TestAction); + var requestDelegate = RequestDelegateFactory.Create((Action)TestAction, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -898,7 +911,7 @@ public async Task RequestDelegateWritesComplexReturnValueAsJsonResponseBody(Dele var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = RequestDelegateFactory.Create(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -947,7 +960,7 @@ public async Task RequestDelegateUsesCustomIResult(Delegate @delegate) var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = RequestDelegateFactory.Create(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -990,7 +1003,7 @@ public async Task RequestDelegateWritesStringReturnValueAsJsonResponseBody(Deleg var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = RequestDelegateFactory.Create(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -1031,7 +1044,7 @@ public async Task RequestDelegateWritesIntReturnValue(Delegate @delegate) var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = RequestDelegateFactory.Create(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -1072,7 +1085,7 @@ public async Task RequestDelegateWritesBoolReturnValue(Delegate @delegate) var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = RequestDelegateFactory.Create(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate, new EmptyServiceProvdier()); await requestDelegate(httpContext); @@ -1110,7 +1123,7 @@ public async Task RequestDelegateThrowsInvalidOperationExceptionOnNullDelegate(D var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = RequestDelegateFactory.Create(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate, serviceProvider: null); var exception = await Assert.ThrowsAnyAsync(async () => await requestDelegate(httpContext)); Assert.Contains(message, exception.Message); @@ -1155,7 +1168,7 @@ public async Task RequestDelegateWritesNullReturnNullValue(Delegate @delegate) var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; - var requestDelegate = RequestDelegateFactory.Create(@delegate); + var requestDelegate = RequestDelegateFactory.Create(@delegate, serviceProvider: null); await requestDelegate(httpContext); @@ -1268,6 +1281,30 @@ public override void Write(byte[] buffer, int offset, int count) } } + private class EmptyServiceProvdier : IServiceScope, IServiceProvider, IServiceScopeFactory + { + public IServiceProvider ServiceProvider => this; + + public IServiceScope CreateScope() + { + return new EmptyServiceProvdier(); + } + + public void Dispose() + { + + } + + public object? GetService(Type serviceType) + { + if (serviceType == typeof(IServiceScopeFactory)) + { + return this; + } + return null; + } + } + private class TestHttpRequestLifetimeFeature : IHttpRequestLifetimeFeature { private readonly CancellationTokenSource _requestAbortedCts = new CancellationTokenSource(); diff --git a/src/Http/Routing/src/Builder/MinimalActionEndpointRouteBuilderExtensions.cs b/src/Http/Routing/src/Builder/MinimalActionEndpointRouteBuilderExtensions.cs index 3db9fbfa98f3..fb538f4d5283 100644 --- a/src/Http/Routing/src/Builder/MinimalActionEndpointRouteBuilderExtensions.cs +++ b/src/Http/Routing/src/Builder/MinimalActionEndpointRouteBuilderExtensions.cs @@ -159,7 +159,7 @@ public static class MinimalActionEndpointRouteBuilderExtensions const int defaultOrder = 0; var builder = new RouteEndpointBuilder( - RequestDelegateFactory.Create(action), + RequestDelegateFactory.Create(action, endpoints.ServiceProvider), pattern, defaultOrder) { diff --git a/src/Http/Routing/test/UnitTests/Builder/MinimalActionEndpointRouteBuilderExtensionsTest.cs b/src/Http/Routing/test/UnitTests/Builder/MinimalActionEndpointRouteBuilderExtensionsTest.cs index 02542f3e8eb8..fec8da0ce7cc 100644 --- a/src/Http/Routing/test/UnitTests/Builder/MinimalActionEndpointRouteBuilderExtensionsTest.cs +++ b/src/Http/Routing/test/UnitTests/Builder/MinimalActionEndpointRouteBuilderExtensionsTest.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Runtime.CompilerServices; using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; using Moq; using Xunit; @@ -28,7 +29,7 @@ private RouteEndpointBuilder GetRouteEndpointBuilder(IEndpointRouteBuilder endpo [Fact] public void MapEndpoint_PrecedenceOfMetadata_BuilderMetadataReturned() { - var builder = new DefaultEndpointRouteBuilder(Mock.Of()); + var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(new EmptyServiceProvdier())); [HttpMethod("ATTRIBUTE")] void TestAction() @@ -60,7 +61,7 @@ string GetMethod(object metadata) [Fact] public void MapGet_BuildsEndpointWithCorrectMethod() { - var builder = new DefaultEndpointRouteBuilder(Mock.Of()); + var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(new EmptyServiceProvdier())); _ = builder.MapGet("/", (Action)(() => { })); var dataSource = GetBuilderEndpointDataSource(builder); @@ -80,7 +81,7 @@ public void MapGet_BuildsEndpointWithCorrectMethod() [Fact] public void MapPost_BuildsEndpointWithCorrectMethod() { - var builder = new DefaultEndpointRouteBuilder(Mock.Of()); + var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(new EmptyServiceProvdier())); _ = builder.MapPost("/", (Action)(() => { })); var dataSource = GetBuilderEndpointDataSource(builder); @@ -100,7 +101,7 @@ public void MapPost_BuildsEndpointWithCorrectMethod() [Fact] public void MapPut_BuildsEndpointWithCorrectMethod() { - var builder = new DefaultEndpointRouteBuilder(Mock.Of()); + var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(new EmptyServiceProvdier())); _ = builder.MapPut("/", (Action)(() => { })); var dataSource = GetBuilderEndpointDataSource(builder); @@ -120,7 +121,7 @@ public void MapPut_BuildsEndpointWithCorrectMethod() [Fact] public void MapDelete_BuildsEndpointWithCorrectMethod() { - var builder = new DefaultEndpointRouteBuilder(Mock.Of()); + var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(new EmptyServiceProvdier())); _ = builder.MapDelete("/", (Action)(() => { })); var dataSource = GetBuilderEndpointDataSource(builder); @@ -148,5 +149,29 @@ public HttpMethodAttribute(params string[] httpMethods) HttpMethods = httpMethods; } } + + private class EmptyServiceProvdier : IServiceScope, IServiceProvider, IServiceScopeFactory + { + public IServiceProvider ServiceProvider => this; + + public IServiceScope CreateScope() + { + return new EmptyServiceProvdier(); + } + + public void Dispose() + { + + } + + public object? GetService(Type serviceType) + { + if (serviceType == typeof(IServiceScopeFactory)) + { + return this; + } + return null; + } + } } }