Add endpoints using reflection in minimal APIs

NT 21 Reputation points
2022-05-12T14:14:23.367+00:00

Hello, i need to migrate a legacy project to the newer .NET 6 and i'm facing a bit of a problem.
The legacy project has 100+ entities that each have at least the basic CRUD endpoints (a lot of them have more specialized endpoints but those can be ignored).
Currently i have code similar to the following

app.MapGet("getUser", async ([FromQuery]Guid id, IMediator mediator) => 
{ 
    return await mediator.Send(new GetUserRequest { Id = id });
});

app.MapPut("addUser", async ([FromBody]AddUserRequest request, IMediator mediator) => 
{
    return await mediator.Send(request);
});

This works fine but adding all endpoints manually is a PITA. I want to automate this. I currently have this method

        public static async Task<TOut> GetById<TIn, TOut>([FromQuery]Guid id, IMediator mediator)
            where TIn : IGetByIdRequest<TOut>
        {
            var request = default(TIn) ?? Activator.CreateInstance<TIn>();
            request.Id = id;

            return await mediator.Send(request);
        }

Coupled with
app.MapGet($"getUser", GetById<GetUserRequest, UserViewModel>).WithName("GetUser").WithTags("User");

This works fine too.
But i was hoping to be able to use reflection on the handlers and automatically add all the endpoints. I am able to get all the information needed but i can't find a way to use that information to add an endpoint.
Currently i was trying to use CreateDelegate to pass to MapGet but CreateDelegate needs a Type which i can't get.
So far i've got

var method = typeof(Helper).GetMethod(nameof(GetById))!;
var typed = method.MakeGenericMethod(endpoint.requestType, endpoint.responseType);

But i don't know how to get something to feed the MapGet method.
The ideal solution would be something like

            var method = typeof(Helper).GetMethod(nameof(GetById))!;
            var typed = method.MakeGenericMethod(endpoint.requestType, endpoint.responseType);
            var del = typed.CreateDelegate();
            app.MapGet(endpoint.pattern, del).WithName(endpoint.name).WithTags(endpoint.tag);

But i'm guessing it's not that easy. Can anyone help with this or has another way of achieving the goal?

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,312 questions
.NET Runtime
.NET Runtime
.NET: Microsoft Technologies based on the .NET software framework.Runtime: An environment required to run apps that aren't compiled to machine language.
1,126 questions
0 comments No comments
{count} votes

Accepted answer
  1. Bruce (SqlWork.com) 57,166 Reputation points
    2022-05-12T15:12:57.14+00:00

    The MakeGenericMethod is used to create a method info to call a generic method. It does not create a generic method, this is done by the compiler. to create the method at runtime you would use the codedom service to create and compile the generic method:

    https://learn.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/dynamic-source-code-generation-and-compilation

    it might be more practical to write a small source code generator that used reflection to write a file, rather than compile at runtime.


0 additional answers

Sort by: Most helpful