中间件DI错误

时间:2018-01-08 20:20:02

标签: c# dependency-injection asp.net-core

我正在尝试实现此post中提到的API密钥验证程序。我遇到了一个问题,我在中间件类中使用注入的服务进行验证返回:

InvalidOperationException:无法从根提供程序解析'FoosballKeepr.Services.Interfaces.ILeagueService',因为它需要作用域服务'FoosballKeepr.Data.FoosballKeeprContext'。

我相信我正在Startup.cs中正确注册我的dbContext,服务和存储库。

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        //MVC
        services.AddMvc();

        //Database
        var connection = @"Server=localhost\SQLEXPRESS;Database=FoosballKeepr;Trusted_Connection=True;";
        services.AddDbContext<FoosballKeeprContext>(options => options.UseSqlServer(connection));

        //Services
        services.AddTransient<IPlayerService, PlayerService>();
        services.AddTransient<ILeagueService, LeagueService>();

        //Repositories
        services.AddTransient<IPlayerRepository, PlayerRepository>();
        services.AddTransient<ILeagueRepository, LeagueRepository>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMiddleware<ApiKeyValidatorMiddleware>();

        app.UseMvc();
    }
}

自定义中间件验证器:

public class ApiKeyValidatorMiddleware
{
    private readonly RequestDelegate _next;
    private ILeagueService _leagueService;

    public ApiKeyValidatorMiddleware(RequestDelegate next, ILeagueService leagueService)
    {
        _next = next;
        _leagueService = leagueService;
    }

    public async Task Invoke(HttpContext context)
    {
        if (!context.Request.Headers.Keys.Contains("x-api-key"))
        {
            context.Response.StatusCode = 400;              
            await context.Response.WriteAsync("API Key Missing.");
            return;
        }
        else
        {
            int leagueId = _leagueService.ValidateApiKey(context.Request.Headers["x-api-key"]);

            if (leagueId == 0)
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsync("Invalid API Key");
                return;
            }
            else
            {
                context.Items["LeagueId"] = leagueId;
            }
        }

        await _next.Invoke(context);
    }
}

服务

    public class LeagueService : ILeagueService
{
    private readonly ILeagueRepository _leagueRepository;

    public LeagueService(ILeagueRepository leagueRepository)
    {
        _leagueRepository = leagueRepository;
    }

    public int ValidateApiKey(string apiKey)
    {
        return _leagueRepository.ValidateApiKey(apiKey);
    }
}

存储库

public class LeagueRepository : ILeagueRepository
{
    private readonly FoosballKeeprContext _context;

    public LeagueRepository(FoosballKeeprContext context)
    {
        _context = context;
    }

    public int ValidateApiKey(string apiKey)
    {
        var query = from l in _context.League
                    where l.ApiKey == apiKey
                    select l.LeagueId;

        return query.FirstOrDefault();
    }
}

这是我第一次实现自定义中间件功能,所以我觉得我的问题没有在正确的上下文中正确设置,但没有任何东西突然出现。这对任何人来说都很熟悉吗?

1 个答案:

答案 0 :(得分:5)

问题是中间件没有范围,因为:

  

Middleware is constructed once per application lifetime

因此,当您需要注入作用域服务时,可以在Invoke操作中执行此操作(所谓的方法注入):

public async Task Invoke(HttpContext context, ILeagueService service)
{
    //...
}