如何在 class 库中使用依赖注入?
How to use Dependency Injection in a class library?
我已经将 Microsoft 依赖注入安装到 .NET Framework 4.8 class 库中。我还注册了接口 A 到 class A。问题是当我尝试创建 class?那么如何让 DI 系统在没有真正入口点的 class 库中提供这个对象?
public Class B
{
B(){InterfaceA}
}
public Class A : InterfaceA
{}
public MainClass
{
public void DoStuff()
{
DependencyContainer.Register();
var myB = new B();
}
}
public DependencyContainer
{
public void Register()
{
(new ServiceCollection()).AddTransient<InterfaceA, A>();
}
}
此致
好的,所以依赖注入并不神奇。您的 Register
方法正在构建服务集合并将其丢弃。你需要真正从容器中解析你的组件(我不是直接说,但容器必须参与)。
您应该使用 BuildServiceProvider
方法从中构建一个 IServiceProvider
:
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<InterfaceA, A>();
serviceCollection.AddTransient<B>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var b = serviceProvider.GetRequiredService<B>(); // constructs B and injects A
可能您应该在 Main 方法中执行此操作,然后将 B(或创建 B 的 Func)注入 MainClass
:
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<MainClass>();
serviceCollection.AddTransient<InterfaceA, A>();
serviceCollection.AddTransient<B>();
serviceCollection.AddTransient<Func<B>>(provider => () => provider.GetRequiredService<B>()); // factory method
var serviceProvider = serviceCollection.BuildServiceProvider();
// ask the container for MainClass and then call DoStuff
var mainClass = serviceProvider.GetRequiredService<MainClass>();
mainClass.DoStuff();
}
然后你可以像这样重写 MainClass:
public class MainClass
{
private readonly B _bInstance;
private readonly Func<B> _bFactory = new Func<B>();
// if you want to create instances of B as and when, I'd suggest using a factory
// otherwise you can pass in a single instance
// I've done both here as an example
public MainClass(Func<B> bFactory, B bInstance)
{
_bInstance = bInstance;
_bFactory = bFactory;
}
public void DoStuff()
{
// create two instances of B
var b1 = _bFactory();
var b2 = _bFactory();
}
}
虽然我提倡在您需要动态构建实例时使用工厂,但可以将 IServiceProvider
自身注入您的 类,然后调用它的 GetRequiredService
或 GetService
方法。我不这样做的原因是因为它是 considered to be an anti-pattern。使用工厂允许您仍然在组合根(即 Main
中)进行更改,而无需在创建 B
.
实例的任何地方进行编辑
DI 意味着任何依赖项都将从外部进入(注入)。 class 本身甚至不知道使用了依赖注入。在您的情况下,应该重写 classes 以接受依赖项而不是创建它们:
public Class B
{
public A MyA {get;}
public B(InterfaceA a)
{
MyA=a;
}
}
public Class A : InterfaceA
{}
public MainClass
{
public B MyB {get;}
public MainClass(B b)
{
MyB=b;
}
public void DoStuff()
{
MyB......;
}
}
class他们对 DI 一无所知。当请求 MainClass
实例时,例如 services.GetRequiredService<MyClass>()
,DI 容器将创建所有必要的实例并将它们传递给 classes。
所有 .NET Core 库的通用模式是提供可用于在主应用程序的 Startup
class 或 ConfigureServices
代表。为此,只需要 Microsoft.Extensions.DependencyInjection.Abstractions
包中的 IServicesCollection
接口。无需添加完整的 DI 包:
public static class MyLibServiceExtensions
{
public static IServicesCollection AddMyClasses(this IServicesCollection services)
{
services.AddTransient<ClassB>()
.AddTransient<InterfaceA,ClassA>()
.AddTransient<MainClass>();
return services;
}
}
现在可以使用它来注册 classes,例如在控制台应用程序中:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddMyClasses()
.AddHostedService<Worker>();
});
}
或者网络应用的Startup.ConfigureServices
方法:
public class Startup
{
public Startup(IWebHostEnvironment env)
{
HostingEnvironment = env;
}
public IWebHostEnvironment HostingEnvironment { get; }
public void ConfigureServices(IServiceCollection services)
{
...
services.AddMyClasses();
}
}
classes 现在将被注入到 DI 容器生成的任何 class 中,例如 `Controller:
public class MyController:ControllerBase
{
public MyController(MyDbContext dbContext,MainClass main)
{
_db=dbContext;
_main=main;
}
}
我已经将 Microsoft 依赖注入安装到 .NET Framework 4.8 class 库中。我还注册了接口 A 到 class A。问题是当我尝试创建 class?那么如何让 DI 系统在没有真正入口点的 class 库中提供这个对象?
public Class B
{
B(){InterfaceA}
}
public Class A : InterfaceA
{}
public MainClass
{
public void DoStuff()
{
DependencyContainer.Register();
var myB = new B();
}
}
public DependencyContainer
{
public void Register()
{
(new ServiceCollection()).AddTransient<InterfaceA, A>();
}
}
此致
好的,所以依赖注入并不神奇。您的 Register
方法正在构建服务集合并将其丢弃。你需要真正从容器中解析你的组件(我不是直接说,但容器必须参与)。
您应该使用 BuildServiceProvider
方法从中构建一个 IServiceProvider
:
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<InterfaceA, A>();
serviceCollection.AddTransient<B>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var b = serviceProvider.GetRequiredService<B>(); // constructs B and injects A
可能您应该在 Main 方法中执行此操作,然后将 B(或创建 B 的 Func)注入 MainClass
:
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<MainClass>();
serviceCollection.AddTransient<InterfaceA, A>();
serviceCollection.AddTransient<B>();
serviceCollection.AddTransient<Func<B>>(provider => () => provider.GetRequiredService<B>()); // factory method
var serviceProvider = serviceCollection.BuildServiceProvider();
// ask the container for MainClass and then call DoStuff
var mainClass = serviceProvider.GetRequiredService<MainClass>();
mainClass.DoStuff();
}
然后你可以像这样重写 MainClass:
public class MainClass
{
private readonly B _bInstance;
private readonly Func<B> _bFactory = new Func<B>();
// if you want to create instances of B as and when, I'd suggest using a factory
// otherwise you can pass in a single instance
// I've done both here as an example
public MainClass(Func<B> bFactory, B bInstance)
{
_bInstance = bInstance;
_bFactory = bFactory;
}
public void DoStuff()
{
// create two instances of B
var b1 = _bFactory();
var b2 = _bFactory();
}
}
虽然我提倡在您需要动态构建实例时使用工厂,但可以将 IServiceProvider
自身注入您的 类,然后调用它的 GetRequiredService
或 GetService
方法。我不这样做的原因是因为它是 considered to be an anti-pattern。使用工厂允许您仍然在组合根(即 Main
中)进行更改,而无需在创建 B
.
DI 意味着任何依赖项都将从外部进入(注入)。 class 本身甚至不知道使用了依赖注入。在您的情况下,应该重写 classes 以接受依赖项而不是创建它们:
public Class B
{
public A MyA {get;}
public B(InterfaceA a)
{
MyA=a;
}
}
public Class A : InterfaceA
{}
public MainClass
{
public B MyB {get;}
public MainClass(B b)
{
MyB=b;
}
public void DoStuff()
{
MyB......;
}
}
class他们对 DI 一无所知。当请求 MainClass
实例时,例如 services.GetRequiredService<MyClass>()
,DI 容器将创建所有必要的实例并将它们传递给 classes。
所有 .NET Core 库的通用模式是提供可用于在主应用程序的 Startup
class 或 ConfigureServices
代表。为此,只需要 Microsoft.Extensions.DependencyInjection.Abstractions
包中的 IServicesCollection
接口。无需添加完整的 DI 包:
public static class MyLibServiceExtensions
{
public static IServicesCollection AddMyClasses(this IServicesCollection services)
{
services.AddTransient<ClassB>()
.AddTransient<InterfaceA,ClassA>()
.AddTransient<MainClass>();
return services;
}
}
现在可以使用它来注册 classes,例如在控制台应用程序中:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddMyClasses()
.AddHostedService<Worker>();
});
}
或者网络应用的Startup.ConfigureServices
方法:
public class Startup
{
public Startup(IWebHostEnvironment env)
{
HostingEnvironment = env;
}
public IWebHostEnvironment HostingEnvironment { get; }
public void ConfigureServices(IServiceCollection services)
{
...
services.AddMyClasses();
}
}
classes 现在将被注入到 DI 容器生成的任何 class 中,例如 `Controller:
public class MyController:ControllerBase
{
public MyController(MyDbContext dbContext,MainClass main)
{
_db=dbContext;
_main=main;
}
}