question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add API to turn delegate or MethodInfo into a RequestDelegate

See original GitHub issue

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

  1. Wrapping a fixed Delegate
  2. MethodInfo with or without “this”

Enhanced routing (MapAction) with is number 1, MVC controllers are examples of number 2.

  1. 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

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:27
  • Comments:9 (8 by maintainers)

github_iconTop GitHub Comments

6reactions
halter73commented, Mar 24, 2021

Don’t expose this building block and expose it on more places. Middleware, Routing, IApplicationBuilder etc.

We should expose this building block. I see no reason to be overly prescriptive and make it difficult for developers to get at this RequestDelegate. We shouldn’t assume we can think of all the ways developers might possibly want to use it. If we don’t expose this, people will do hacks like build a whole middleware pipeline just to get at a RequestDelegate.

We don’t technically need all of these overloads. Build(MethodInfo methodInfo, Func<HttpContext, object> targetFactory) can be implemented by calling Build(Delegate action) or vice-versa. Efficiently using the Build(Delegate action) overload if you have a nontrivial targetFactory would likely require expression tree compilation or something similarly complicated, so I’m completely fine keeping the other overloads for convenience.

If we do decide to reduce the overloads, Build(Delegate action) is the one I most want to keep though. I think it will see the most usage outside of framework code.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Building the final RequestDelegate
In this post we walk through the RequestDelegateFactory.Create() method, to understand how all the Expressions we've seen are combined into ...
Read more >
How is Delegate being cast to RequestDelegate in ASP. ...
We convert an arbitrary Delegate into a RequestDelegate . That process is complex and generates code at runtime based on the parameters and...
Read more >
Customising the RequestDelegate with filters
In this post, I'm focusing on how filters change the generated RequestDelegate , so we'll start by looking at the delegate for a...
Read more >
RequestDelegateFactory.Create Method
Creates a RequestDelegate implementation for handler.
Read more >
Custom ASP.NET Core Middleware Example
The one dependency common to most middleware is a RequestDelegate object representing the next delegate in the HTTP request processing ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found