question

NT-5477 avatar image
0 Votes"
NT-5477 asked NT-5477 commented

Add endpoints using reflection in minimal APIs

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?

dotnet-csharpdotnet-runtime
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

Bruce-SqlWork avatar image
0 Votes"
Bruce-SqlWork answered NT-5477 commented

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://docs.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.



· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Yes, that is the next step. However since no one here knows how to use source generation it seemed faster to use reflection. But source generation is definitely looked at. Thanks for the answer.

0 Votes 0 ·