我有一个 dot net core 2.0 web api。该 API 使用 JWT 授权,通常返回 json 响应。
我将数据库上下文注入(inject)到一个存储库中,然后将存储库注入(inject)到 Controller 构造函数中,它适用于单个请求。
在 Startup.cs 中,我注册了存储库和上下文,如下所示:
services.AddMvc();
services.AddDbContext<SPContext>(cfg => cfg.UseSqlServer(_config["SPConnectionString"]));
services.AddScoped<ISPRepository, SPRepository>();
存储库构造函数:
private SPContext _context { get; }
public SPRepository(SPContext context, ILogger<SPRepository> logger)
{
_context = context;
_logger = logger;
}
Controller 构造函数:
private static ISPRepository _repository;
public ChartsController( ILogger<ChartsController> logger, ISPRepository repository)
{
_repository = repository;
_logger = logger;
}
在我的方法中,我有:
[HttpGet]
[Route("api/v1/charts/dashboard/my")]
public async Task<IActionResult> GetMyDashboards()
{
SPUser user = _repository.GetUserByOid(this.User.Identity.Name);
return Ok(_repository.GetMyDashboards(user));
}
对于此方法的单个 GET 请求,我得到了一个没有错误的结果,如果我在发送下一个请求之前等待执行完成,它也能正常工作。
在测试期间,我碰巧有多个请求同时发送到这条路由。结果是对第一个错误的响应,然后是对其余错误的“500”错误。
错误日志显示错误为:
System.InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
但是,如果我将存储库注入(inject)方法,而不是 Controller :
[HttpGet]
[Route("api/v1/charts/dashboard/my")]
public async Task<IActionResult> GetMyDashboards([FromServices]ISPRepository _repository)
{
SPUser user = _repository.GetUserByOid(this.User.Identity.Name);
return Ok(_repository.GetMyDashboards(user));
}
然后请求全部成功,即使同时触发也是如此。
我的理解是,注册为作用域的对象仅在单个请求的生命周期内可用,并且当新请求进入系统时将创建一个新实例。因此,根据我的理解,第二个请求应该导致创建一组新对象。
我注册服务或 Controller 的方式有问题吗?或者这是依赖注入(inject)的预期行为?
最佳答案
您应该删除 Controller 中 _repository 上的“static”属性。因为这意味着您的 Controller 的所有实例将共享同一个存储库。
当您在第一个请求仍在处理中时发出第二个请求时, 您将使用存储库的新实例创建 Controller 的新实例。这很好,但是因为 _repository 是静态的,它也将通过替换之前创建的 Controller 与 Controller 的第一个实例共享。
然后两个 Controller 将调用相同的底层 DbContext,从而导致您的问题。
当您手动注入(inject)存储库时,一切都是分离的,这就是它适合您的原因。
一个好的做法是让你的属性只读,以确保它们只在构造函数中初始化一次,以后不能被覆盖。
private readonly ISPRepository _repository;
关于c# - DotNet 核心 Web API 依赖注入(inject)范围和处置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51183167/