Search code examples
c#asp.net-coredependency-injectionminimal-apiscarter

Minimal API Service not injected using .NET Carter


I´m creating an API in .NET using Carter. I have this Module Defined:

    public class VariationsModule : EntityModule<Variation>
    {
        public VariationsModule()
        {
            this.MainRoute = "api/variations";
        }

        public override Task AddEntity(HttpContext context, [FromBody] Variation entity, [FromServices] IEntityService<Variation> entityService)
        {
            return base.AddEntity(context, entity, entityService);
        }
}

Where EntityModule contains common methods to all the entities that I´m planning to add and is defined like:

public abstract class EntityModule<TEntity> : ModuleBase where TEntity : Entity

It also provides the basic endpoints for the modules:

public override void AddRoutes(IEndpointRouteBuilder app)
{
    app.MapGet(this.MainRoute, this.GetEntities);
    app.MapPost(this.MainRoute, this.AddEntity);
    app.MapGet(this.MainRoute + "/{id:guid}", this.GetEntity);
    app.MapPut(this.MainRoute + "/{id:guid}", this.UpdateEntity);
    app.MapDelete(this.MainRoute + "/{id:guid}", this.DeleteEntity);
} 

Module base is the implementation of the ICarterModule interface

The problem basically is that the IEntityService<Variation> in the VariationsModule is null so it's not correctly injected.

This is the definition of the Variations Service:

public class VariationsService : EntityService<Variation>, IVariationsService

IVariationsService inherits from IEntityService<Variation>:

public interface IVariationsService : IEntityService<Variation>

Where EntityService<T> is:

public abstract class EntityService<TEntity> : IEntityService<TEntity> where TEntity : Entity

And then the Service is added in the DI Container like:

    builder.Services.AddScoped<IVariationsService, VariationsService>();

Am I missing something? First why do I need to specify [FromServices] in the Add method? Secondly how can I fix this problem? Might be an architectural problem?


Solution

  • builder.Services.AddScoped<IVariationsService, VariationsService>(); will not register IEntityService<Variation> it will only register IVariationsService. One approach is to scrap VariationsService with interface completely and just register the open generic (if EntityService is not abstract and it's implementation is satisfactory):

     builder.Services.AddScoped(typeof(IEntityService<>), typeof(EntityService<>));
    

    If you want specific registration then you will need to register it:

    builder.Services.AddScoped<IEntityService<Variation>, VariationsService>();
    

    If you need it by both interfaces then:

    builder.Services.AddScoped<IVariationsService, VariationsService>();
    builder.Services.AddScoped<IEntityService<Variation>>(sp => sp.GetRequiredService<VariationsService>());