ASP.NET Core中检测Controller依赖缺失的简单办法

来自:DotNet技术栈知识分享,作者:Lamond Lu

背景

当在ASP.NET Core中使用依赖注入时,如果不使用自动服务注册, 开发人员很容易忘记在Startup.cs文件中添加代码注册指定服务。这种问题很容易修复,但是很难检测,通常都是遇到报错了再去修改。

在开发模式下,我们希望尽可能的检测所有的依赖。这里我给大家介绍一种检测Controller中的依赖缺失的简单方案。

如何检测Controller的依赖缺失

首先你需要在Startup.ConfigureServices注入一个日志访问器, 我们将使用它在控制台显示出缺失的依赖

private readonly ILogger<Startup> _logger;

public Startup(ILogger<Startup> logger, IConfiguration configuration)
{
    Configuration = configuration;
    _logger = logger;
}

然后我们需要以服务的形式注册所有的Controller。

services
    .AddMvc()
    .AddControllersAsServices()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

最后我们在ConfigureService方法的末尾添加如下代码:

var controllers = Assembly.GetExecutingAssembly().GetTypes()
    .Where(type => typeof(ControllerBase).IsAssignableFrom(type))
    .ToList();

var sp = services.BuildServiceProvider();
foreach (var controllerType in controllers)
{
    _logger.LogInformation($"Found {controllerType.Name}");
    try
    {
        var controller = sp.GetService(controllerType);
    }
    catch (System.Exception ex)
    {
        _logger.LogCritical(ex, 
            $"Cannot create instance of controller {controllerType.FullName}, it is missing some services");
    }
}

测试

为了测试这个检测是否成功,我们下面来添加一个接口IFooRepository和实现该接口的类FooRepository

public interface IFooRepository
{
    string GetWords();
}

public class FooRepository : IFooRepository
{
    public string GetWords()
    
{
        return "Hello World!";
    }
}

然后我们在ValuesController中添加构造器注入

public class ValuesController : ControllerBase
{
    private IFooRepository _fooRepository { get; set; }

    public ValuesController(IFooRepository fooRepository)
    
{
        _fooRepository = fooRepository;
    }

    ...
}

然后我们不注册IFooRepository, 直接启动项目

错误输出如下:

info: DIChecking.Startup[0]
      Found ValuesController
crit: DIChecking.Startup[0]
      Cannot create instance of controller DIChecking.Controllers.ValuesController, it is missing some services
System.InvalidOperationException: Unable to resolve service for type 'DIChecking.IFooRepository' while attempting to activate 'DIChecking.Controllers.ValuesController'.
推荐↓↓↓
iOS开发