Structuremap ObjectFactory.GetAllInstances<IHandle <TEvent >> ()

Я испытываю трудности с реализацией событий в недавнем проекте.

Я проверил, что structmap сканирует правильно, собирает и добавляет EventHandlers

Scan(cfg =>
            {
               cfg.TheCallingAssembly();
                cfg.IncludeNamespace("ABC.EventHandler");
                cfg.ConnectImplementationsToTypesClosing(typeof(IHandle<>));

           });

 public class StructureMapEventDispatcher : IEventDispatcher
    {

        public void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent
        {

            foreach (var handler in ObjectFactory.GetAllInstances<IHandle<TEvent>>())
            {

                handler.Handle(eventToDispatch);

            }

        }

    }

Раньше я запускал Event из домена. Что-то вроде Dispatcher.RaiseEvent(new [domainEvent class](x,y,z));

и событие будет запущено. Мне пришлось изменить дизайн, где я сейчас собираю события в коллекции

_domainEvents = new Collection<IDomainEvent>();

и затем подняв его после того, как я сохранил домен в хранилище

 public static void Raise(ICollection<IDomainEvent> domainEvents)
        {
            foreach (var domainEvent in domainEvents)
            {
                DomainEventDispatcher.Raise(domainEvent);
            }

        }

но сейчас

ObjectFactory.GetAllInstances<IHandle<TEvent>>() возвращает 0 счетчиков обработчиков

если я буду наблюдать за

ObjectFactory.GetAllInstances<IHandle<DomainEventClass>>() это возвращает коллекцию обработчиков должным образом (в настоящее время у меня есть 2, и это показывает 2 счета)

... Я предполагаю, что это как-то связано с событиями типа IDomainEvent вместо фактического типа, и это усложняет структурную карту, чтобы решить это.

Как я могу решить эту проблему?

С Уважением,

Мар

-

Изменить 1:

Я подтвердил, что контейнер struturemap содержит все обработчики событий, отсканированные из сборки.

Редактировать 2

Я не знаю, как заставить этот вопрос привлечь больше внимания. Я добавляю награду за решение для достижения желаемых результатов. Если вопрос не понятен, пожалуйста, задавайте.

В основном я хочу ObjectFactory.GetAllInstances<IHandle<TEvent>>() вернуть обработчики для TEvent где TEvent имеет тип IDomainEvent, События, которые будут подняты, хранятся в коллекции IDomainEvent и поднял после того, как Домен был сохранен (из уровня обслуживания).

Я думаю, что должен быть какой-то способ заставить структуру структуры знать, что событие возникло как IDomainEvent на самом деле типа DomainEvent

var eventsToRaise= dealerr.EventsToRaise(); Добавление информации из окна отладки:

После того, как события были подняты в окне диспетчера

Изменить 3: Eventhough eventToRaise отображается как "DealerName Changed" и "DealerCommunicationChanged"
typeof (TEvent) дает тип как Domain.IDomainEvent

Я догадываюсь, возможно ли получить возможность приводить к нужному типу (из окна наблюдения ВС, где появляется информация) проблема может быть решена

----- Результат ---

Оба подхода сработали. Я связал обоих с двумя другими членами в моей команде, и мы чувствовали, что это решение, не задумываясь, будет выбрано как правильный ответ.

Сегодня мы проведем тестирование с измененной реализацией и посмотрим, есть ли какие-либо проблемы с этим решением в решении.

Я проголосовал за решение, основанное на рефлексии, так как это также правильный ответ.


2 ответа

Решение

Вместо подхода, основанного на рефлексии, я бы рекомендовал использовать запись для хранения информации о типе. Что-то вроде этого:

interface IEventRecord
{
    void Dispatch(IEventDispatcher dispatcher);
}

public class EventRecord<TEvent> : IEventRecord where TEvent : IDomainEvent
{
    TEvent theEvent;

    public EventRecord(TEvent theEvent)
    {
        this.theEvent = theEvent;
    }

    public void Dispatch(IEventDispatcher dispatcher)
    {
        dispatcher.Dispatch(theEvent);
    }
}

Если вы находите создание экземпляров записей событий громоздким, помощник может вывести параметр типа следующим образом:

public static EventRecord<TEvent> CreateEventRecord<TEvent>(TEvent theEvent) where TEvent : IDomainEvent
{
    return new EventRecord<TEvent>(theEvent);
}

Который позволил бы вам создавать экземпляры записей о событиях следующим образом:

var record = CreateEventRecord(myDomainEvent);

Тогда вместо того, чтобы держаться за коллекцию IDomainEvents, держись за коллекцию IEventRecords которые содержат необходимые данные типа, чтобы поднять себя:

foreach (var eventRecord in Records)
{
    eventRecord.Dispatch(myDispatcher);
}

Как вы говорите, проблема в том, что вы запрашиваете структуру карты для всех случаев IHandle<IDomainEvent> и он не имеет ни одного из них, Structuremap имеет обработчики для конкретных событий. Вам нужно будет создать тип, используя фактический тип события, а затем запросить все обработчики этого события:

        Type genericHandler = typeof(IHandle<>);
        Type[] typeArgs = { eventToDispatch.GetType() };
        Type neededHandler = genericHandler.MakeGenericType(typeArgs);
        var handlers = ObjectFactory.GetAllInstances(neededHandler);

проблема в том, что вы в конечном итоге получаете IList объектов, и вам нужно привести их к правильному типу обработчика, и это становится немного сложнее.... возможное решение состоит в использовании отражения для вызова Handle() метод:

        var methodInfo = neededHandler.GetMethod("Handle");
        object[] methodArgs = new object[] { eventToDispatch };
        foreach (var h in handlers)
        {
            methodInfo.Invoke(h, methodArgs);
        }
Другие вопросы по тегам