I'm trying to automate the implementation of the CRUD for my application.
I'm using the Minimal API design, and I wrote a ICrudService<T> which can Get, Single, Add, Update and Delete the T Entity.
Now I'm trying to automate the endpoints part. I'm able to have the Get and the Single working with this code :
Type[] types =
{
typeof(Place),
typeof(PlaceLink),
};
foreach (var type in types)
{
var scope = app.Services.CreateScope();
var serviceType = typeof(ICrudService<>).MakeGenericType(type);
dynamic service = scope.ServiceProvider.GetService(serviceType);
app
.MapGet($"/{type.Name.ToLower()}s", async () =>
{
var result = await service.Get();
return Results.Ok(result);
})
.WithTags($"{type.Name}s");
app
.MapGet($"/{type.Name.ToLower()}s/" + "{id}", async (int id) =>
{
var result = await service.Single(id);
return Results.Ok(result);
})
.WithTags($"{type.Name}s");
}
Which gives me the swagger I want :

But I'm struggling with the Add (and probably with the Update one).
Here is the actual code for the Add part :
app
.MapPost($"/{type.Name.ToLower()}s/" + "{id}", async(TYPE_OF_ENTITY entity) =>
{
var result = await service.Add(entity);
return Results.Ok(result);
})
.WithTags($"{type.Name}s");
I'm able to get the service by using the .MakeGenericType(type) function. But here, the async(TYPE_OF_ENTITY entity) is a signature for an anonymous function, and I don't know if there is any trick I can use to specify the Type of the entity var by using the type var.
The dynamic keyword works, but Swagger isn't able to know the Type of my entity, so the GUI appears raw without any default schema for the request :
how can I dynamically create the signature of my anonymous function ?

To perform dynamic Minimal API registration you can move the setup into a generic method and then call it via reflection. For example:
class MapExts
{
public static void MapType<T>(WebApplication app)
{
Type type = typeof(T);
app
.MapGet($"/{type.Name.ToLower()}s", async (ICrudService<T> service) =>
{
var result = await service.Get();
return Results.Ok(result);
})
.WithTags($"{type.Name}s");
app
.MapGet($"/{type.Name.ToLower()}s/" + "{id}", async (int id, ICrudService<T> service) =>
{
var result = await service.Single(id);
return Results.Ok(result);
})
.WithTags($"{type.Name}s");
app
.MapPost($"/{type.Name.ToLower()}s/" + "{id}", async (T entity, ICrudService<T> service) =>
{
var result = await service.Add(entity);
return Results.Ok(result);
})
.WithTags($"{type.Name}s");
}
}
And usage:
var mapMethod = typeof(MapExts).GetMethod(nameof(MapExts.MapType));
foreach (var type in types)
{
mapMethod.MakeGenericMethod(type).Invoke(null, new object?[] { app });
}
P.S.
This:
var scope = app.Services.CreateScope();
var serviceType = typeof(ICrudService<>).MakeGenericType(type);
dynamic service = scope.ServiceProvider.GetService(serviceType);
is bad. Not only due to using dynamic type (which can be opinionated claim) but this will result in the same instance of service handling all requests for the app lifetime which can lead to a lot of different issues depending on the actual service implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With