Только для тестирования и дидактического дирекции, не имеющего строгой привязки к этому вопросу, я писал пятиминутное консольное приложение для отправки события в RabbitMQ с использованием Rebus.Моя цель - только опубликовать событие, но у меня есть некоторые проблемы при регистрации шины с помощью WindsorCastle.На моей работе у нас есть несколько Windows Service Jobs, которые делают это изящным образом, сейчас дома возникают проблемы с чем-то, что кажется мне простым, но я думаю, что мне не хватает некоторых основ IOC, может быть ...
ЭтоProgram.cs, в котором я использую попросить WindsorCastle установить контейнер для IOC:
using Castle.Windsor;
using Serilog;
using System;
namespace RebusRabbitEmitEvent
{
public class Program
{
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.ColoredConsole(outputTemplate: "{Timestamp:HH:mm:ss} {Message}{NewLine}{Exception}")
.CreateLogger();
using (var container = new WindsorContainer())
{
container
.Install(new Installer());
EventEmitter emitter = container.Resolve<EventEmitter>();
emitter.Emit();
Console.WriteLine("Press ENTER to quit");
Console.ReadLine();
}
}
}
}
Вот Installer.cs, в котором я установил все DI:
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using Rebus.Activation;
using Rebus.Bus;
using Rebus.Config;
using Rebus.Retry.Simple;
namespace RebusRabbitEmitEvent
{
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IBus>()
.UsingFactoryMethod(k =>
{
var cnstring = "amqp://guest:guest@localhost:5672";
var inputQueueName = "Pippo.Input";
var errorQueueName = "Pippo.Error";
return Configure.With(k.Resolve<IHandlerActivator>())
.Logging(l => l.ColoredConsole())
.Transport(t => t.UseRabbitMq(cnstring, inputQueueName))
.Routing(r => r.TypeBasedRoutingFromAppConfig())
.Options(o => o.SimpleRetryStrategy(errorQueueAddress: errorQueueName, maxDeliveryAttempts: 2))
.Options(o => o.SetNumberOfWorkers(1))
.Options(o => o.SetMaxParallelism(1))
.Start();
}).LifestyleSingleton(),
Component.For<IHandlerActivator>()
.UsingFactoryMethod(k => new CastleWindsorContainerAdapter(container)),
Component.For<EventEmitter>()
.UsingFactoryMethod(k =>
{
return new EventEmitter(k.Resolve<IBus>());
})
);
}
}
}
Вот EventEmitter.cs, в котором я публикую событие:
using Rebus.Bus;
using RebusRabbitEmitEvent.Events;
using System;
public class EventEmitter
{
private IBus _bus = null;
public EventEmitter(IBus bus)
{
_bus = bus;
}
public void Emit()
{
_bus.Publish(new OperationDoneEvent(Guid.NewGuid(), 0, "Valore del parametro")).Wait();
}
}
Здесь код события:
using System;
namespace RebusRabbitEmitEvent.Events
{
public interface IEvent
{
Guid Id { get; }
}
[Serializable]
public class Event : IEvent
{
public Guid Id { get; private set; }
public int Version;
public Event(Guid id, int version)
{
this.Id = id;
this.Version = version;
}
}
public class OperationDoneEvent : Event
{
public string ParameterPassedThroughEvent { get; protected set; }
public OperationDoneEvent(Guid id, int version, string parameterPassedThroughEvent) : base(id, version)
{
ParameterPassedThroughEvent = parameterPassedThroughEvent;
}
}
}
Когда я запускаю программу, я получаю исключение на Installer.cs во время возвратаConfigure.With (k.Resolve ()) , исключение говорит: « System.InvalidOperationException:« Служба IBus уже зарегистрирована в этом контейнере. Если вы хотите разместить несколько экземпляров Rebus в одном процессе,используйте для них отдельные экземпляры контейнеров. ' "
Любой другой объект инъекции зависимостей, который я тестирую, отлично работает.+ Если я не использую WindsorCastle и не устанавливаю шину непосредственно в EventEmitter.cs, программа работает хорошо.
Есть ли что-то не так?Что я неправильно понимаю?
ОБНОВЛЕНИЕ:
Я скачал исходный код Rebus.CastleWindsor.Я вижу, что с моим кодом при нажатии CastleWindsorContainerAdapter у windsorContainer уже есть IBus:
Я попытался немного изменить установщик, удалить заводской методIBus и создания IBus непосредственно в заводском методе EventEmitter, например:
Component.For<EventEmitter>()
.UsingFactoryMethod(k =>
{
var cnstring = "amqp://guest:guest@localhost:5672";
var inputQueueName = "Pippo.Input";
var errorQueueName = "Pippo.Error";
IBus bus = Configure.With(new CastleWindsorContainerAdapter(container))
.Logging(l => l.ColoredConsole())
.Transport(t => t.UseRabbitMq(cnstring, inputQueueName))
.Routing(r => r.TypeBasedRoutingFromAppConfig())
.Options(o => o.SimpleRetryStrategy(errorQueueAddress: errorQueueName, maxDeliveryAttempts: 2))
.Options(o => o.SetNumberOfWorkers(1))
.Options(o => o.SetMaxParallelism(1))
.Start();
return new EventEmitter(bus);
})
Теперь в ctor CastleWindsorContainerAdapter, в windsorContainer больше нет IBus:
С этим изменением метод SetBus CastleWindsorContainerAdapter не выдает исключение, и код работает.
А этот момент я немного запутался, я думал, что оригинал был вправильно, я догадался, что в «вернуть новый EventEmitter (k.Resolve ());»в решении использовался бы заводской метод IBus, я видел много Windows Service с аналогичным установщиком, повторяю, может быть, мне не хватает некоторых основ IOC, или, может быть, что-то особенное в этой ситуации ..?
ОБНОВЛЕНИЕ 2:
Как указано в mookid8000 в его комментарии к ответу, IBUS не должен повторно обрабатываться в контейнере, как, впрочем, и в его ответе (и примере в документации).Выкладываю полный правильный установщик для наглядности:
namespace RebusRabbitEmitEvent
{
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
Configure.With(new CastleWindsorContainerAdapter(container))
.Logging(l => l.ColoredConsole())
.Transport(t => t.UseRabbitMq("amqp://guest:guest@localhost:5672", "Pippo.Input"))
.Routing(r => r.TypeBasedRoutingFromAppConfig())
.Options(o => o.SimpleRetryStrategy(errorQueueAddress: "Pippo.Error", maxDeliveryAttempts: 2))
.Options(o => o.SetNumberOfWorkers(1))
.Options(o => o.SetMaxParallelism(1))
.Start();
container.Register(
Component.For<EventEmitter>()
.UsingFactoryMethod(k =>
{
return new EventEmitter(k.Resolve<IBus>());
})
);
}
}