[英]DotNetCore WebAPI Dependency Injection Scope and Disposal
我有一個dot net core 2.0 web api。 API使用JWT授權,通常返回json響應。
我將數據庫上下文注入存儲庫,然后將存儲庫注入控制器構造函數,它適用於單個請求。
在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.
但是,如果我將存儲庫注入方法,而不是控制器:
[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));
}
然后請求全部成功,即使同時被解雇。
我的理解是,注冊為作用域的對象僅在單個請求的生命周期內可用,並且當新請求進入系統時將創建新實例。 因此,根據我的理解,第二個請求應該導致創建一組新對象。
注冊服務或控制器的方式有問題嗎? 或者這是依賴注入的預期行為?
您應該刪除控制器中_repository的'static'屬性。 因為這意味着控制器的所有實例將共享同一個存儲庫。
當第一個請求仍在處理時觸發第二個請求時,您將使用存儲庫的新實例創建控制器的新實例。 這很好,但是因為_repository是靜態的,所以它也將與控制器的第一個實例共享,替換之前創建的實例。
然后兩個控制器將調用相同的底層DbContext,從而導致您的問題。
當您手動注入存儲庫時,所有內容都是分開的,這就是為什么它適合您。
一個好的做法是使您的屬性只讀,以確保它們只在構造函數中初始化一次,並且以后不能覆蓋。
private readonly ISPRepository _repository;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.