ASP.NET Core 依赖注入 ValidateOnBuild 无法正常工作

pam*_*a84 1 c# dependency-injection asp.net-core .net-5

我有一个使用 RazorPages 的 .NET 5 项目,我设置此代码来验证 Progam.cs 文件中的依赖注入:

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseDefaultServiceProvider(options =>
            {
                options.ValidateOnBuild = true;
                options.ValidateScopes = true;
            })....
Run Code Online (Sandbox Code Playgroud)

我忘记注册注入到我的页面中的服务,所以我预计当我尝试启动应用程序时,错误页面会显示此类问题,但我不明白为什么它不会发生,因为例如,如果我不注册 ILocalizerService ,就会发生这种情况: 这是我的 RazorPage:

public class SignupModel : IdentityPageModel
{
    [BindProperty]
    public Models.Account.Signup Signup { get; set; }

    private readonly CustomUserManager _userManager;
    private readonly ILogger<SignupModel> _logger;
    private readonly INcsService _ncsService;

    public SignupModel(CustomUserManager userManager, 
        ILogger<SignupModel> logger,
        INcsService ncsService) : base(localizerService)
    {
        Guard.Against.Null(userManager, nameof(userManager));

        Guard.Against.Null(logger, nameof(logger));
        Guard.Against.Null(ncsService, nameof(ncsService));
        
        _userManager = userManager;
        _logger = logger;
        _ncsService = ncsService;
    }

    // Other code....
}
Run Code Online (Sandbox Code Playgroud)

这是我的服务:

[PublicAPI]
public class NcsService : INcsService
{
    private readonly IHttpClientFactory _httpClientFactory;

    public NcsService(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    // Other code...
}
Run Code Online (Sandbox Code Playgroud)

我只注册了 IHttpClientFactory 而没有注册 INcsService 接口和实现:

services.AddHttpClient(nameof(NcsService), client =>
{
    client.BaseAddress = new Uri(ncsSettings.BaseUri);
    client.DefaultRequestHeaders.Add("x-functions-key", ncsSettings.ApiKey);
    client.DefaultRequestHeaders.Add("x-app-name", "TSID");

}).AddHeaderPropagation(options =>
{
    options.Headers.Add("x-request-id");
    options.Headers.Add("x-correlation-id");
})
.AddPolicyHandler(GetRetryPolicy());
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 5

问题的根源是 Microsoft 的默认IComponentActivator实现(DefaultComponentActivator)。组件激活器控制创建 Razor 页面,但内置行为不会从内置容器请求这些页面。相反,它只是使用 Activator.CreateInstance创建它们。

这意味着 Blazor 不会内置容器中注册您的页面,因此该页面不会成为容器验证过程的一部分。

在我看来,这是 Blazor 中的一个设计缺陷,因为众所周知,并且众所周知,如果您使用 DI 容器,则应该让所有应用程序组件都通过容器管道。这是容器可以为您提供有关应用程序组件有效性的合理确定性的唯一方法。

然而,Blazor 并不是 ASP.NET Core 框架中唯一发生这种情况的部分。例如,ASP.NET MVC 控制器默认情况下不会在容器中注册,也不会从容器中解析。虽然这是可配置的,但由于这不是默认行为,因此ValidateOnBuild给人一种错误的安全感。

其他容器可能有更合理的默认值。例如,Simple Injector(我维护的容器)包含始终预先注册所有 MVC 控制器的扩展方法。通过 Blazor 集成,类似的事情也会发生。

如果您坚持使用内置容器,最好确保所有组件都从容器中解析。使用 MVC 这很容易,因为您可以简单地调用AddControllersAsServices. 不幸的是,对于 Blazor,这要困难得多,因为不存在这样的方法AddComponentsAsServices。这意味着您必须创建一个IComponentActivator回调容器的自定义。但是,您仍然可能必须回退到使用Activator.CreateInstanceMicrosoft 创建的所有 Blazor 组件的原始行为,因为使用反射查找和注册它们可能要困难得多。有关如何创建此类自定义组件激活器并注册应用程序 Blazor 组件的灵感,请查看此处提供的代码。