Description
Background and Motivation
MVC Controllers have this magic power baked inside of them to allow dispatching HTTP requests to an arbitrarily shaped method on a controller (called actions). As part of the work to make this more accessible, we want to expose a zero dependency building block from lower in the stack that enables the same thing with arbitrary methods and delegates. This lets library authors build convenient and complex request handling logic without having to take big dependencies on controllers or mvc.
Proposed API
namespace Microsoft.AspNetCore.Http
{
+ public sealed class RequestDelegateFactory
+ {
+ public static RequestDelegate Create(Delegate requestHandler);
+ public static RequestDelegate Create(MethodInfo methodInfo, Func<HttpContext, object> targetFactory);
+ public static RequestDelegate Create(MethodInfo methodInfo);
+ }
}
Usage Examples
There are 2 scenarios
- Wrapping a fixed Delegate
- MethodInfo with or without "this"
Enhanced routing (MapAction) with is number 1, MVC controllers are examples of number 2.
- Dispatch with delegate
Func<string> hello = () => "Hello World";
RequestDelegate rd1 = RequestDelegateFa.Build(hello);
app.Run(rd1);
RequestDelegate rd2 = RequestDelegateFactory.Create(Func<string>)MyClass.Hello);
app.Run(rd2);
public class MyClass
{
public static string Hello() => "Hello World";
}
2a. Class dispatch with instance
MethodInfo methodInfo = typeof(MyClass).GetMethod(nameof(MyClass.Hello));
// This will create an instance of MyClass per request, giving the factory a chance to construct
// MyClass using per request scoped objects
RequestDelegate rd1 = RequestDelegateFactory.Create(methodInfo, context => new MyClass());
// Example with DI
RequestDelegate rd2 = RequestDelegateFactory.Create(methodInfo, context => context.RequestServices.GetRequiredService<MyClass>());
app.Run(rd1);
app.Run(rd2);
public class MyClass
{
public string Hello() => "Hello World";
}
2a. Class dispatch with static
MethodInfo methodInfo = typeof(MyClass).GetMethod(nameof(MyClass.Hello));
RequestDelegate rd = RequestDelegateFactory.Create(methodInfo);
app.Run(rd);
public class MyClass
{
public static string Hello() => "Hello World";
}
Alternatives
Don't expose this building block and expose it on more places. Middleware, Routing, IApplicationBuilder etc.
PS: We might also need to consider options that control behavior in the future.
cc @pranavkm