在.NET Core库项目中,我如何将一个类注入到另一个类中? 在哪里配置DI,就像在API项目的StartUp Class ConfigureServices中一样?
在.NET Core库项目中,我如何将一个类注入到另一个类中? 在哪里配置DI,就像在API项目的StartUp Class ConfigureServices中一样?
在进行了大量搜索之后,我没有找到一个带有示例的全面答案来回答这个问题。以下是在类库中使用 DI 的步骤。
在您的类库中:
public class TestService : ITestService
{
private readonly ITestManager _testManager;
public TestService(ITestManager testManager)
{
_testManager = testManager;
}
}
public class TestManager : ITestManager
{
private readonly ITestManager _testManager;
public TestManager()
{
}
}
然后在库中扩展IServiceCollection:
public static class ServiceCollectionExtensions
{
public static void AddTest(this IServiceCollection services)
{
services.AddScoped<ITestManager, TestManager>();
services.AddScoped<ITestService, TestService>();
}
}
最后,在主应用程序 StartUp(API、控制台等)中:
public void ConfigureServices(IServiceCollection services)
{
services.AddTest();
}
ServiceCollectionExtensions
,只需在 API/控制台应用程序的 ConfigureServices
方法中使用 services.AddScoped<ITestManager, TestManager>();
即可。我尝试过了,它可以无缝运行。 - Kumar针对如何管理这一问题,有许多思考过程,因为最终,调用方需要为您注册DI(依赖注入)处理过程。
如果您观察微软和其他公司使用的方法,通常会定义一个扩展方法,并将其作为“AddMyCustomLibrary”这样的方法添加到IServiceCollection中。关于此问题有一些讨论请参见此处。
我不确定我完全理解你的意图……但也许你可以让你的实现自己创建一个私有的 ServiceProvider
,像这样:
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public class MyBlackBox {
private readonly IServiceProvider _services = BuildServices();
protected MyBlackBox() {}
public static MyBlackBox Create() {
return _services.GetRequiredService<MyBlackBox>();
}
private static void ConfigureServices(IServiceCollection services) {
services.AddTransient<MyBlackBox>();
// insert your dependencies here
}
private static IServiceProvider BuildServices() {
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
serviceCollection.AddOptions();
serviceCollection.AddSingleton(config);
serviceCollection.AddSingleton<IConfiguration>(config);
ConfigureServices(serviceCollection);
return serviceCollection.BuildServiceProvider();
}
private static IConfigurationRoot BuildConfig() {
var path = Directory.GetCurrentDirectory();
var builder = new ConfigurationBuilder().SetBasePath(path).AddJsonFile("appsettings.json");
return builder.Build();
}
}
您可以在“父”ServiceProvider
上注册您的实现,这样您的依赖关系就不会在它上注册。
缺点是,您将不得不重新配置所有内容,主要是日志记录和配置。
如果您需要访问来自父ServiceProvider
的某些服务,您可以创建绑定它们的东西:
public static void BindParentProvider(IServiceProvider parent) {
_services.AddSingleton<SomeService>(() => parent.GetRequiredService<SomeService>());
}
我很确定有更好的方法创建嵌套的ServiceProvider
,不过。
依赖注入是在组合根处配置的,基本上是应用程序的入口点。如果您无法控制应用程序的入口点,则无法强制任何人使用依赖注入来使用您的类库。但是,您可以使用基于接口的编程并创建帮助类来为您的类库中的每个类型注册各种组合根场景,这将允许人们使用IOC来实例化您的服务,而不管他们正在创建哪种类型的程序。
您可以使类库中的服务依赖于库中其他服务的接口,以便自然地使用它们将其注册到使用的容器中,并允许更有效的单元测试。
[assembly: HostingStartup(typeof(HostingStartupLibrary.ServiceKeyInjection))]
namespace HostingStartupLibrary
{
public class Startup : IHostingStartup
{
public void Configure(IWebHostBuilder builder)
{
builder.ConfigureServices((context, services) => {
services.AddSingleton<ServiceA>();
});
}
}
}
这样我就可以调用已经附加了服务的库,直接使用它们。
这对我很有效:
public class LibraryBase
{
ctor... (múltiple services)
public static IHostBuilder CreateHostBuilder(IHostBuilder host)
{
return host.ConfigureServices(... services)
}
}
主函数:
public class Program
{
Main{... ConfigureServicesAsync()}
private static async Task ConfigureServicesAsync(string[] args)
{
IHostBuilder? host = new HostBuilder();
host = Host.CreateDefaultBuilder(args);
LibraryBase.CreateHostBuilder(host);
host.ConfigureHostConfiguration()
// ... start app
await host.StartAsync();
}
}
https://dotnetcoretutorials.com/2017/01/24/servicecollection-extension-pattern/
如果您在类库中编写此扩展程序,可以在其中注入类/服务。
IServiceCollection
扩展来抽象化这个过程,但实际调用它的应该是应用程序。 - Chris Pratt