在 Development 環(huán)境下依賴注入的行為可能有所不同
奇怪的問題
本周被一個奇怪的問題困擾了一天。事情的起因是這樣的:在某個 PR 合并后,我拉了最新代碼,但是在我本地F5調試始終報錯。示例代碼如下:
public interface Interface1
{
void Method1();
}
public class MockSerivce
{
public MockSerivce(Interface1 interface1)
{
}
}
builder.Services.AddSingleton<MockSerivce>();
報的錯誤呢也顯而易見:
Unable to resolve service for type 'DevelopmentTest.Interface1' while attempting to activate 'DevelopmentTest.MockSerivce'
我們沒有注冊 Interface1 到 DI 容器里,那自然實例化 MockSerivce 的時候就找不到依賴了。
但是奇怪的是:我其他同事們都沒有這個問題,他們在本地調試的時候都好好的,并不會報錯。并且在這個分支編譯后的代碼在開發(fā)服務器上運行的都很完美。
這個就有點沖擊到我了,難道是我電腦有問題,VS 有問題,還是我人品有問題?
尋找答案
當然了代碼是不會騙人的,造成以上問題一定不是我人品問題而是代碼的問題。
經過一番嘗試,我發(fā)現(xiàn)這個問題跟系統(tǒng)運行在哪個環(huán)境有關系。只要我把 launchSettings.json 里的 ASPNETCORE_ENVIRONMENT 從 Development 改成別的什么值,那么一切都運行正常了。正巧在我們組其他同事都維護一個自己的 appestings.username.json 然后運行在這個環(huán)境之下,也就是說他們都不運行在 Development 下。這就是為啥只有我會報錯的原因了。
事情到了這一步,那么我們很容易猜測: .NET DI 系統(tǒng)在 Development 下是有騷操作的。在 Development 下它會進行依賴分析,如果依賴關系有錯誤,那么直接會報錯。但是在其他環(huán)境下就不會提交分析校驗,只有在運行時真正嘗試實例化對象的時候才會報錯。
當然靠猜測總是不太靠譜,干脆翻翻代碼吧。很快就找到了:
internal static ServiceProviderOptions CreateDefaultServiceProviderOptions(HostBuilderContext context)
{
bool isDevelopment = context.HostingEnvironment.IsDevelopment();
return new ServiceProviderOptions
{
ValidateScopes = isDevelopment,
ValidateOnBuild = isDevelopment,
};
}
在 HostingHostBuilderExtensions 這個擴展類里很清楚的看到,只有在 Development 下 DefaultServiceProviderOptions 的 ValidateScopes 與 ValidateOnBuild 會被設置為 True。這就直接證明了上面的猜想。只有在 Development 下才會在啟動的時候去校驗依賴關系。
強制校驗
既然找到了答案,那么讓我們來試一下:強制開啟依賴關系的校驗。
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseDefaultServiceProvider(op =>
{
op.ValidateOnBuild = true;
op.ValidateScopes = true;
});
代碼如上在 Host 上調用 UseDefaultServiceProvider 擴展方法,指定 ValidateScopes 與 ValidateOnBuild 都為 True。
再次運行我們的項目,這個時候不管是在 Development 還是 Production 還是別的任何環(huán)境下,都會報錯了。
Unable to resolve service for type 'DevelopmentTest.Interface1' while attempting to activate 'DevelopmentTest.MockSerivce'
總結
通過以上我們可以發(fā)現(xiàn) .NET 的 DI 系統(tǒng),在 Development 環(huán)境下跟其他環(huán)境的行為是不同的。在 Development 下會提交進行依賴關系的校驗,如果有問題會提前報錯。所以我們調試的時候請盡量選擇在 Development 下進行或者手動強制開啟校驗。這個問題很容易被忽視,至少我沒在其他博文里見有人提到過。其實在微軟的官方文檔上是提到了,但也確實就是提了一嘴而已。
關于這個話題其實還沒完,還有一個更有意思的問題:Captive dependency 可以聊一下。但是今天太晚了,改天吧。
參考:https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#scope-validation
QQ群:1022985150 VX:kklldog 一起探討學習.NET技術
作者:Agile.Zhou(kklldog)
出處:http://www.rzrgm.cn/kklldog/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

浙公網安備 33010602011771號