【发布时间】:2018-01-08 20:20:02
【问题描述】:
我正在尝试实现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();
}
}
这是我第一次实现自定义中间件功能,所以我觉得我的问题是没有在正确的上下文中正确设置某些东西,但没有什么明显的弹出。有没有人觉得这很眼熟??
【问题讨论】:
-
附带说明:除非您有特定原因(即将来会放弃 EF)将 EF 放在存储库后面,否则不要这样做。另一个注意事项:EF6 和 EF Core 包含用于 I/O 绑定操作的
Async方法,您应该使用它们而不是同步版本。另一个注意事项(可能会解决您的问题),您的服务和存储库应该是AddScoped而不是AddTransient -
只是一个想法,但如果
services.AddTransient<ILeagueRepository, LeagueRepository>();在services.AddTransient<ILeagueService, LeagueService>();之前会有所不同,因为该服务依赖于存储库。 -
@CamiloTerevinto 将 EF 放在存储库后面有什么问题。它抽象了逻辑并提供了简单的方法来调用以访问数据。
-
@pmcilreavy 问题是大多数人都弄错了,成为一个巨大的维护负担,而 EF 已经实现了存储库(
DbContext本身)和工作单元(每个DbSet)。 EF 非常简单,我不知道如何通过将其隐藏在另一层之后使其更简单。 -
@SBFrancies 我尝试重新订购仍然收到完全相同的错误。
标签: c# dependency-injection asp.net-core