[英]Using Dependency Injection in .NET Core Service application
我们在.net核心中有一个基于服务的应用程序,它将在Linux环境中作为守护程序运行。 一切都按预期工作,但我在处理依赖项注入时遇到问题。 下面是参考代码
Program.cs中
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Starting PreProcessor Application ");
try
{
ConfigParameters.LoadSettings(args);
}
catch (Exception ex)
{
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine($"Error in setting config parameters {ex.Message}");
return;
}
IHost host = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddLogging();
services.AddHostedService<MainService>();
services.AddTransient<IMessageQueue, ActiveMQHandler>(x =>
{
return new ActiveMQHandler(ConfigParameters.Settings.MessageQueueAddress);
});
services.AddTransient<IMessageQueue, ActiveMQHandler>(x =>
{
return new ActiveMQHandler(ConfigParameters.Settings.MessageQueueAddress);
});
services.AddTransient<IMessageQueue, ActiveMQHandler>(x =>
{
return new ActiveMQHandler(ConfigParameters.Settings.MessageQueueAddress);
});
})
.Build();
await host.RunAsync();
}
}
MainService
构造函数如下所示
IApplicationLifetime appLifetime;
IConfiguration configuration;
PreProcessorQueueListener listener;
private string reason = "SHUTDOWN SIGNAL";
private IMessageQueue messageQueue;
private IMessageQueue messageQueueSL;
private IMessageQueue messageQueueSLProcess;
public MainService(IConfiguration configuration, IApplicationLifetime appLifetime, IMessageQueue messageQueue, IMessageQueue messageQueueSL, IMessageQueue messageQueueSLProcess)
{
this.configuration = configuration;
this.messageQueue = messageQueue;
this.messageQueueSL = messageQueueSL;
this.messageQueueSLProcess = messageQueueSLProcess;
this.appLifetime = appLifetime;
}
如果您在MainService
代码中看到,我正在使用构造函数依赖项注入为IMessageQueue
接口传递三个实例。 我真正想要的是基于应用程序任何部分的需求,我可以通过传递IMessageQueue
接口来获取ActiveMQHandler
类的新实例。 由于我无法为此找到解决方案,因此我传递了三个IMessageQueue
实例(对此解决方案我不满意)。 如果我需要使用的其他实例ActiveMQHandler
类,那么我将不得不第四个参数为传递IMessageQueue
接口在我MainService
类。
我真正在寻找的是使用ServiceProvider
(或更优雅的东西),并使用它来获取实现IMessageQueue
接口的类的新实例/单例(基于Program.cs
定义)。
一个建议的家伙?
如果将MainService构造函数签名更改为
public MainService(IConfiguration configuration, IApplicationLifetime appLifetime, IEnumerable<IMessageQueue> messageQueues)
您将能够访问所有三个接口实现。
问题可能在于是否需要从列表中识别它们,例如对每个实现执行不同的操作。 如果您需要对每个实现执行相同的操作,那么它将起作用。
否则,您应该考虑使用通用类型来区分注入的实现。
只需将构造函数更改为包含IEnumerable<IMessageQueue>
。 它应该为您提供所有已注册IMessageQueue实现者的列表。
我个人不喜欢在类中依赖IApplicationLifetime或IServiceProvider。 这有点像ServiceLocator反模式。
您可以将IServiceProvider
注入到类中,然后使用Microsoft.Extensions.DependencyInejction
命名空间中的GetServices(typeof(IMessageQueue))
或扩展函数GetServices<IMessageQueue>()
。 所以像这样:
public MainService(IConfiguration configuration, IApplicationLifetime appLifetime, IServiceProvider serviceProvider)
{
this.configuration = configuration;
messageQueue = serviceProvider.GetServices<IMessageQueue>();
messageQueueSL = serviceProvider.GetServices<IMessageQueue>();
messageQueueSLProcess = serviceProvider.GetServices<IMessageQueue>();
this.appLifetime = appLifetime;
}
根据您使用IMessageQueue
确切目的,可能会有更优雅的解决方案。 似乎IMessageQueue
用于某种日志记录。 例如,假设您需要为SLProcess
和SL
是不同类的每个类SLProcess
一个消息队列。 对于这种情况,您可以注入泛型。 因此,您可以定义以下内容:
interface IMessageQueue<T> : IMessageQueue { }
class ActiveMQHandler<T> : ActiveMQHandler, IMessageQueue<T> {
public string targetType => typeof(T).ToString();
}
有了这个,您应该能够注入如下内容: AddTransient(typeof(IMessageQueue<>), typeof(ActiveMQHandler<>))
。
最后,我提供了一个我认为很优雅且不依赖于构造函数DI的解决方案。 想法是让服务(是的,我们有一个微服务体系结构)在IServiceCollection
创建依赖关系的集合,一旦服务启动,只要任何类想要解析依赖关系,它们都将传入Interface
并获取具体实例。类。 我的最终代码是这样的。 我在公共库中创建了一个单独的类
public class DependencyInjection
{
private static ServiceProvider Provider;
public static void AddServices(IServiceCollection services)
{
Provider = services.BuildServiceProvider();
}
public static T GetService<T>()
{
var serviceScopeFactory = Provider.GetRequiredService<IServiceScopeFactory>();
using (var scope = serviceScopeFactory.CreateScope())
{
return scope.ServiceProvider.GetService<T>();
}
}
}
现在我在Program.cs
文件中的Main
方法看起来像这样
static async Task Main(string[] args)
{
Console.WriteLine("Starting PreProcessor Application ");
IServiceCollection servicesCollection = new ServiceCollection();
try
{
ConfigParameters.LoadSettings(args);
servicesCollection.AddScoped<IMessageQueue, ActiveMQHandler>(x =>
{
return new ActiveMQHandler("127.0.0.1");
});
DependencyInjection.AddServices(servicesCollection);
}
catch (Exception ex)
{
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine($"Error in setting config parameters {ex.Message}");
return;
}
IHost host = new HostBuilder()
.ConfigureHostConfiguration(configHost =>
{
configHost.AddCommandLine(args);
})
.ConfigureServices((hostContext, services) =>
{
services.AddLogging();
services.AddHostedService<MainService>();
})
.Build();
await host.RunAsync();
}
现在在项目中的任何地方,当我需要ActiveMQHandler类的实例时,我只需编写以下代码行
var messageQueue = DependencyInjection.GetService<IMessageQueue>();
只是在我的信息Program.cs
我使用AddScoped
但我已经测试了代码AddSingleton
也和每次我要求的具体类实例是相同的。
此链接上的文章https://stackify.com/net-core-dependency-injection/帮助了我
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.