Skip to content

Commit 4c0513e

Browse files
committed
Detect services based on service provider
- As a final fallback, try to detect services from the DI container before falling back to body behavior.
1 parent 72779f8 commit 4c0513e

File tree

4 files changed

+108
-55
lines changed

4 files changed

+108
-55
lines changed

src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ static Microsoft.AspNetCore.Http.HeaderDictionaryTypeExtensions.AppendList<T>(th
169169
static Microsoft.AspNetCore.Http.HeaderDictionaryTypeExtensions.GetTypedHeaders(this Microsoft.AspNetCore.Http.HttpRequest! request) -> Microsoft.AspNetCore.Http.Headers.RequestHeaders!
170170
static Microsoft.AspNetCore.Http.HeaderDictionaryTypeExtensions.GetTypedHeaders(this Microsoft.AspNetCore.Http.HttpResponse! response) -> Microsoft.AspNetCore.Http.Headers.ResponseHeaders!
171171
static Microsoft.AspNetCore.Http.HttpContextServerVariableExtensions.GetServerVariable(this Microsoft.AspNetCore.Http.HttpContext! context, string! variableName) -> string?
172-
static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Delegate! action) -> Microsoft.AspNetCore.Http.RequestDelegate!
173-
static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo) -> Microsoft.AspNetCore.Http.RequestDelegate!
174-
static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo, System.Func<Microsoft.AspNetCore.Http.HttpContext!, object!>! targetFactory) -> Microsoft.AspNetCore.Http.RequestDelegate!
172+
static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Delegate! action, System.IServiceProvider! serviceProvider) -> Microsoft.AspNetCore.Http.RequestDelegate!
173+
static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo, System.IServiceProvider! serviceProvider) -> Microsoft.AspNetCore.Http.RequestDelegate!
174+
static Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(System.Reflection.MethodInfo! methodInfo, System.IServiceProvider! serviceProvider, System.Func<Microsoft.AspNetCore.Http.HttpContext!, object!>! targetFactory) -> Microsoft.AspNetCore.Http.RequestDelegate!
175175
static Microsoft.AspNetCore.Http.ResponseExtensions.Clear(this Microsoft.AspNetCore.Http.HttpResponse! response) -> void
176176
static Microsoft.AspNetCore.Http.ResponseExtensions.Redirect(this Microsoft.AspNetCore.Http.HttpResponse! response, string! location, bool permanent, bool preserveMethod) -> void
177177
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!

src/Http/Http.Extensions/src/RequestDelegateFactory.cs

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,27 @@ public static class RequestDelegateFactory
6262
/// Creates a <see cref="RequestDelegate"/> implementation for <paramref name="action"/>.
6363
/// </summary>
6464
/// <param name="action">A request handler with any number of custom parameters that often produces a response with its return value.</param>
65+
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> instance used to detect which parameters are services.</param>
6566
/// <returns>The <see cref="RequestDelegate"/>.</returns>
66-
public static RequestDelegate Create(Delegate action)
67+
public static RequestDelegate Create(Delegate action, IServiceProvider serviceProvider)
6768
{
6869
if (action is null)
6970
{
7071
throw new ArgumentNullException(nameof(action));
7172
}
7273

74+
if (serviceProvider is null)
75+
{
76+
throw new ArgumentNullException(nameof(serviceProvider));
77+
}
78+
7379
var targetExpression = action.Target switch
7480
{
7581
object => Expression.Convert(TargetExpr, action.Target.GetType()),
7682
null => null,
7783
};
7884

79-
var targetableRequestDelegate = CreateTargetableRequestDelegate(action.Method, targetExpression);
85+
var targetableRequestDelegate = CreateTargetableRequestDelegate(action.Method, serviceProvider, targetExpression);
8086

8187
return httpContext =>
8288
{
@@ -88,15 +94,21 @@ public static RequestDelegate Create(Delegate action)
8894
/// Creates a <see cref="RequestDelegate"/> implementation for <paramref name="methodInfo"/>.
8995
/// </summary>
9096
/// <param name="methodInfo">A static request handler with any number of custom parameters that often produces a response with its return value.</param>
97+
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> instance used to detect which parameters are services.</param>
9198
/// <returns>The <see cref="RequestDelegate"/>.</returns>
92-
public static RequestDelegate Create(MethodInfo methodInfo)
99+
public static RequestDelegate Create(MethodInfo methodInfo, IServiceProvider serviceProvider)
93100
{
94101
if (methodInfo is null)
95102
{
96103
throw new ArgumentNullException(nameof(methodInfo));
97104
}
98105

99-
var targetableRequestDelegate = CreateTargetableRequestDelegate(methodInfo, targetExpression: null);
106+
if (serviceProvider is null)
107+
{
108+
throw new ArgumentNullException(nameof(serviceProvider));
109+
}
110+
111+
var targetableRequestDelegate = CreateTargetableRequestDelegate(methodInfo, serviceProvider, targetExpression: null);
100112

101113
return httpContext =>
102114
{
@@ -108,15 +120,21 @@ public static RequestDelegate Create(MethodInfo methodInfo)
108120
/// Creates a <see cref="RequestDelegate"/> implementation for <paramref name="methodInfo"/>.
109121
/// </summary>
110122
/// <param name="methodInfo">A request handler with any number of custom parameters that often produces a response with its return value.</param>
123+
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> instance used to detect which parameters are services.</param>
111124
/// <param name="targetFactory">Creates the <see langword="this"/> for the non-static method.</param>
112125
/// <returns>The <see cref="RequestDelegate"/>.</returns>
113-
public static RequestDelegate Create(MethodInfo methodInfo, Func<HttpContext, object> targetFactory)
126+
public static RequestDelegate Create(MethodInfo methodInfo, IServiceProvider serviceProvider, Func<HttpContext, object> targetFactory)
114127
{
115128
if (methodInfo is null)
116129
{
117130
throw new ArgumentNullException(nameof(methodInfo));
118131
}
119132

133+
if (serviceProvider is null)
134+
{
135+
throw new ArgumentNullException(nameof(serviceProvider));
136+
}
137+
120138
if (targetFactory is null)
121139
{
122140
throw new ArgumentNullException(nameof(targetFactory));
@@ -128,15 +146,15 @@ public static RequestDelegate Create(MethodInfo methodInfo, Func<HttpContext, ob
128146
}
129147

130148
var targetExpression = Expression.Convert(TargetExpr, methodInfo.DeclaringType);
131-
var targetableRequestDelegate = CreateTargetableRequestDelegate(methodInfo, targetExpression);
149+
var targetableRequestDelegate = CreateTargetableRequestDelegate(methodInfo, serviceProvider, targetExpression);
132150

133151
return httpContext =>
134152
{
135153
return targetableRequestDelegate(targetFactory(httpContext), httpContext);
136154
};
137155
}
138156

139-
private static Func<object?, HttpContext, Task> CreateTargetableRequestDelegate(MethodInfo methodInfo, Expression? targetExpression)
157+
private static Func<object?, HttpContext, Task> CreateTargetableRequestDelegate(MethodInfo methodInfo, IServiceProvider serviceProvider, Expression? targetExpression)
140158
{
141159
// Non void return type
142160

@@ -154,7 +172,10 @@ public static RequestDelegate Create(MethodInfo methodInfo, Func<HttpContext, ob
154172
// return default;
155173
// }
156174

157-
var factoryContext = new FactoryContext();
175+
var factoryContext = new FactoryContext()
176+
{
177+
ServiceProvider = serviceProvider
178+
};
158179

159180
var arguments = CreateArguments(methodInfo.GetParameters(), factoryContext);
160181

@@ -234,6 +255,17 @@ private static Expression CreateArgument(ParameterInfo parameter, FactoryContext
234255
}
235256
else
236257
{
258+
if (factoryContext.ServiceProvider != null)
259+
{
260+
using var scope = factoryContext.ServiceProvider.CreateScope();
261+
262+
// If the parameter resolves as a service then get it from services
263+
if (scope.ServiceProvider.GetService(parameter.ParameterType) is not null)
264+
{
265+
return Expression.Call(GetRequiredServiceMethod.MakeGenericMethod(parameter.ParameterType), RequestServicesExpr);
266+
}
267+
}
268+
237269
return BindParameterFromBody(parameter.ParameterType, allowEmpty: false, factoryContext);
238270
}
239271
}
@@ -788,6 +820,7 @@ private class FactoryContext
788820
{
789821
public Type? JsonRequestBodyType { get; set; }
790822
public bool AllowEmptyRequestBody { get; set; }
823+
public IServiceProvider? ServiceProvider { get; set; }
791824

792825
public bool UsingTempSourceString { get; set; }
793826
public List<(ParameterExpression, Expression)> TryParseParams { get; } = new();

0 commit comments

Comments
 (0)