How to pass type variable value into delegate parameter

75 Views Asked by At

I am creating an dotnet core C# Web API app using wolverine (probably not important)

Each Command is configured in program like so by Mapping a Post.

public record CreateIssue(Guid OriginatorId, string Title, string Description);
public record AssignIssue(Guid IssueId, Guid AssigneeId);
...
app.MapPost("/issues/create", (CreateIssue body, IMessageBus bus) => bus.InvokeAsync(body));
app.MapPost("/issues/assign", (AssignIssue body, IMessageBus bus) => bus.InvokeAsync(body));

I wanted to make this configuration free and just have it work whenever I create a new command.

I get all of types of command

var commands = typeof(CreateIssue).GetTypeInfo().Assembly.GetExportedTypes()
    .Where(t => t.Namespace == typeof(CreateIssue).GetTypeInfo().Namespace)
    .Where(t => t.GetMethod("<Clone>$") is object); //isRecord

Then I loop on these types

foreach (Type command in commands)
{
    app.MapPost($"/command/{command.Name}", (??? body, IMessageBus bus) => bus.InvokeAsync(body))
        .Accepts(command, "application/json").Produces(StatusCodes.Status200OK);
}

My problem is I need to set the body to the command type (??? above) so that it can model bind. How can I accomplish this?

1

There are 1 best solutions below

0
4imble On

So I managed to get this working.

in Program I call a new extension method

app.MapWolverineCommands();

Then the extension method looks like this:

using System.Reflection;
using Wolverine.Web.Server.Commands;

namespace Wolverine.Web.Server;

public static class WebAppExtensions
{
    public static void MapWolverineCommands(this WebApplication app)
    {
        var commands = typeof(CreateIssue).GetTypeInfo().Assembly.GetExportedTypes()
            .Where(t => t.Namespace == typeof(CreateIssue).GetTypeInfo().Namespace)
            .Where(t => t.GetMethod("<Clone>$") is object); //isRecord

        var method = typeof(WebAppExtensions).GetMethod(nameof(MapCommand), BindingFlags.NonPublic | BindingFlags.Static)!;
        foreach (var command in commands)
        {
            var generic = method.MakeGenericMethod(command);
            generic.Invoke(null, new object[] { app });
        }
    }
    
    static void MapCommand<TCommand>(WebApplication app)
    {
        app.MapPost($"/command/{typeof(TCommand).Name}", 
             (TCommand body, IMessageBus bus) => bus.InvokeAsync(body));
    }
}

This is good enough that I can also drop the calls to .Accepts<TCommand>("application/json").Produces(StatusCodes.Status200OK); which I added to allow Swagger to know the generic types but this has become redundant.