ASP.NET Core 5 - 如何拥有可选依赖项?

ASP.NET Core 5 - How to have optional dependencies?

我正在开发一个中间件,我希望它具有对内部日志记录库的可选依赖性。换句话说,如果 MyLoggingService 已注册,太棒了!否则,生活将继续,我将登录到控制台。

但是通过声明 public async Task Invoke(HttpContext httpContext, MyLoggingService logger),我收到一个运行时错误,提示它未注册。我尝试将默认值设置为 null 但这没有用。另外,因为它是一个中间件,我不能重载 Invoke 方法。

除了请求服务集合,自己解决依赖,还有其他解决方案吗?

与其将依赖项设为可选,不如考虑:

  • 抽象编程,例如IMyLoggingService
  • 注册一个Null Object实现

例如:

public class CustomMiddleware1 : IMiddleware
{
    private readonly IMyLoggingService logger;

    public CustomMiddleware1(IMyLoggingService logger) => this.logger = logger;

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        this.logger.Log("Before");

        await next(context);

        this.logger.Log("After");
    }
}

空对象实现:

public sealed class NullMyLoggingService : IMyLoggingService
{
    public void Log(LogEntry e) { }
}

注册人数:

services.AddSingleton<IMyLoggingService>(new NullMyLoggingService());

app.Use<CustomMiddleware1>();

AddSingleton<IMyLoggingService>(new NullMyLoggingService()) 的调用确保 IMyLoggingService 的注册始终存在。这防止了消费者的复杂性,否则他们将不得不为记录器不存在的情况添加条件逻辑。

可以通过简单地在第一个之后添加第二个 IMyLoggingService 来替换此空实现:

services.AddScoped<IMyLoggingService, DbMyLoggingService>();

app.Use<CustomMiddleware1>();

答案非常简单:

public async Task Invoke(HttpContext httpContext, MyLoggingService logger = null)