如何使用 Microsoft.Extension.DependencyInjection 允许可选服务?

Luk*_*ien 9 c# dependency-injection asp.net-core

我在我自己的爱好项目中使用 ASP.NET Core,我想创建一个将由开发人员使用的框架,并且我想允许可选服务并使用未注册的默认值。

我收到Unable to resolve service for type 'XXX'错误,但我希望 DI 返回null而不是抛出异常。我想允许可选服务,因此如果找到服务,请在构造函数中使用它,如果未找到,则将 null 传递给构造函数。

在我的实现中,我有:

public IServiceManager(IService service, ...)
{
    _service = service ?? new DefaultService();
    ...
}
Run Code Online (Sandbox Code Playgroud)

如您所见,如果找不到服务(空),请使用默认值。也许我误解了 DI 的工作原理。也许我可以使用工厂来代替它?但是,在我的系统中,当提供 non 时我使用默认服务将很常见,因此我需要一个不需要 API 使用者注册服务的解决方案。

有没有办法将 ASP.NET Core DI 配置为返回 null 而不是抛出异常?

lai*_*ika 18

在构造函数中为该参数添加默认值。

public IServiceManager(IService service = null, ...)
{
  _service = service ?? new DefaultService();
  ...
}
Run Code Online (Sandbox Code Playgroud)

  • @LukeTO'Brien 与 DI 无关......编译错误清楚地说明了 - C# 中 _any_ 方法的 _any_ 参数的默认值必须是编译时常量 - 即 `null`,而不是 `new Sevice() ` (5认同)
  • 默认值将解决 OP 所写的问题。构造函数的实际实现是完全无关的。顺便说一句,我不是在争论在另一种类型的构造函数中实例化一种类型是否是 DI 模式中的好习惯。 (2认同)
  • 不起作用,至少在net core 3.1中,启动时仍然出现di错误 (2认同)

Tse*_*eng 13

就其本质而言,构造函数注入始终被认为是强制性的。

Microsoft DI 的第一个版本(我不喜欢使用术语 ASP.NET Core DI,因为它不依赖于 ASP.NET Core 并且可以在它之外使用)仅支持具有最多参数的构造函数。

认为从那时起这已经发生了变化,允许多个构造函数,IoC 容器将选择一个合适的构造函数。话虽如此,您可能需要定义多个构造函数。

public IServiceManager(IService service, IOtherService otherService)
{
}

public IServiceManager(IOtherService otherService)
{
}
Run Code Online (Sandbox Code Playgroud)

如果IService没有在 IoC 容器中注册,则应调用第二个构造函数。

但这充其量仍然是一种值得怀疑的做法,并且会使您的代码更难维护和保持其不变/松散耦合。

你永远不应该在你的服务中实例化你的类型,即使是可选服务也是如此。

相反,您应该提供允许用户使用他们自己的实现覆盖它们的注册。

public static IServiceCollection AddMyLibrary(this IServiceCollection services)
{
    services.TryAddTransient<IService, Service>();
    services.TryAddTransient<IOtherService, OtherService>();
}
Run Code Online (Sandbox Code Playgroud)

然后用户覆盖它。

services.AddTransient<IService, CustomService>();
services.AddMyLibrary();
Run Code Online (Sandbox Code Playgroud)

现在CustomService将被注入到IService需要的地方。