我已经创建了一个ASP.NET核心MVC/WebApi站点,它有一个基于JamesStill的博客文章Real-World PubSub Messaging with RabbitMQ的RabbitMQ订阅者。
在他的文章中,他使用了一个静态类来启动队列订阅者并定义队列事件的事件处理程序,然后这个静态方法通过一个静态工厂类示例化事件处理程序类。
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace NST.Web.MessageProcessing
{
public static class MessageListener
{
private static IConnection _connection;
private static IModel _channel;
public static void Start(string hostName, string userName, string password, int port)
{
var factory = new ConnectionFactory
{
HostName = hostName,
Port = port,
UserName = userName,
Password = password,
VirtualHost = "/",
AutomaticRecoveryEnabled = true,
NetworkRecoveryInterval = TimeSpan.FromSeconds(15)
};
_connection = factory.CreateConnection();
_channel = _connection.CreateModel();
_channel.ExchangeDeclare(exchange: "myExchange", type: "direct", durable: true);
var queueName = "myQueue";
QueueDeclareOk ok = _channel.QueueDeclare(queueName, true, false, false, null);
_channel.QueueBind(queue: queueName, exchange: "myExchange", routingKey: "myRoutingKey");
var consumer = new EventingBasicConsumer(_channel);
consumer.Received += ConsumerOnReceived;
_channel.BasicConsume(queue: queueName, noAck: false, consumer: consumer);
}
public static void Stop()
{
_channel.Close(200, "Goodbye");
_connection.Close();
}
private static void ConsumerOnReceived(object sender, BasicDeliverEventArgs ea)
{
// get the details from the event
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
var messageType = "endpoint"; // hardcoding the message type while we dev...
// instantiate the appropriate handler based on the message type
IMessageProcessor processor = MessageHandlerFactory.Create(messageType);
processor.Process(message);
// Ack the event on the queue
IBasicConsumer consumer = (IBasicConsumer)sender;
consumer.Model.BasicAck(ea.DeliveryTag, false);
}
}
}
在我现在需要在消息处理器工厂中解析服务而不仅仅是写入控制台之前,它一直工作得很好。
using NST.Web.Services;
using System;
namespace NST.Web.MessageProcessing
{
public static class MessageHandlerFactory
{
public static IMessageProcessor Create(string messageType)
{
switch (messageType.ToLower())
{
case "ipset":
// need to resolve IIpSetService here...
IIpSetService ipService = ???????
return new IpSetMessageProcessor(ipService);
case "endpoint":
// need to resolve IEndpointService here...
IEndpointService epService = ???????
// create new message processor
return new EndpointMessageProcessor(epService);
default:
throw new Exception("Unknown message type");
}
}
}
}
有没有什么方法可以访问ASP.NET核心IoC容器来解决依赖项?我真的不想手动旋转整个依赖项堆栈:(
或者,是否有更好的方法从ASP.NET核心应用程序订阅RabbitMQ?我找到了RestBus,但它没有针对Core1.x进行更新
7条答案
按热度按时间wwtsj6pe1#
您可以避免使用静态类,并始终使用依赖注入,同时结合使用:
IApplicationLifetime
启动/停止侦听器。IServiceProvider
创建消息处理器的示例。首先,让我们将配置移到它自己的类中,该类可以从appsettings.json中填充:
接下来,将
MessageHandlerFactory
转换为一个非静态类,该类接收一个IServiceProvider
作为依赖项,它将使用服务提供程序来解析消息处理器示例:通过这种方式,消息处理器类可以在构造函数中接收它们需要的任何依赖项(只要在
Startup.ConfigureServices
中配置它们)。例如,我将一个ILogger注入到我的一个示例处理器中:现在把
MessageListener
转换成一个依赖于IOptions<RabbitOptions>
和MessageHandlerFactory
的非静态类,它和你原来的类非常相似,我只是用选项依赖替换了Start方法的参数,处理器工厂现在是一个依赖而不是静态类:到了这里,您需要更新
Startup.ConfigureServices
方法,使它知道您的服务和选项(如果需要,可以为侦听器和处理程序工厂创建接口):最后,更新
Startup.Configure
方法,以获取额外的IApplicationLifetime
参数,并在ApplicationStarted
/ApplicationStopped
事件中启动/停止消息侦听器(尽管我不久前注意到使用IISExpress的ApplicationStopping事件存在一些问题,如在this question中):monwx1rj2#
尽管使用依赖注入是一个更好的解决方案,但在某些情况下,您必须使用静态方法(如扩展方法)。
对于这些情况,您可以向静态类添加静态属性,并在ConfigureServices方法中初始化它。
例如:
和配置服务中:
f87krz0w3#
我知道我的回答晚了,但我想分享我是如何做到的。
首先:使用ServiceLocator是Antipattern,所以尽量不要使用它。在我的例子中,我需要它在我的DomainModel中调用MediatR来实现DomainEvents逻辑。
然而,我必须找到一种方法来调用DomainModel中的静态类,以从DI获取某个注册服务的示例。
因此,我决定使用
HttpContext
来访问IServiceProvider
,但我需要从静态方法访问它,而不在域模型中提及它。我们开始吧:
1-我创建了一个接口来 Package IServiceProvider
2-然后,我创建了一个静态类作为ServiceLocator访问点
3-我创建了
IServiceProviderProxy
的实现,它在内部使用IHttpContextAccessor
4-我应该像这样在DI中注册
IServiceProviderProxy
5-最后一步是在应用程序启动时使用
IServiceProviderProxy
示例初始化ServiceLocator
因此,现在您可以在DomainModel类中调用ServiceLocator“Or and needed place”并解析所需的依赖项。
fcg9iug34#
以下是我对你的情况的看法:
如果可能,我将发送解析的服务作为参数
否则使用寿命将很重要。
如果服务是单例的,我只需要设置configure方法的依赖关系:
如果服务生存期是有范围的,我将使用HttpContextAccessor:
insrf1ej5#
Here是ServiceLocator的一个很好的实现,它也使用了作用域,甚至可以用于IHttpContextAccessor!
只需将this class复制到代码中,然后注册ServiceLocator
**重要说明 :ServiceLocator被视为反模式,因此如果您有任何其他选择,请不要使用它!!!!
polkgigr6#
关于瓦希德·比塔尔的答复
太神奇了!对于.Net Core 6,我在Program.cs上做了:
b1payxdu7#
您可以在
Configure
中获得服务引用:然后将其传递给init函数或在类上设置静态成员
当然,正如其他答案中所解释的,依赖注入将是一个更好的解决方案...