Structuremap ObjectFactory.GetAllInstances() - PullRequest
5 голосов
/ 24 мая 2011

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

Я проверил, что структура карты сканирует правильно, собирает и добавляет 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 содержит всеобработчики событий отсканированы из сборки.

Edit 2

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

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

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

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

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

enter image description here

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

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

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

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

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

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


Ответы [ 2 ]

4 голосов
/ 16 июня 2011

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

        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);
        }
1 голос
/ 16 июня 2011

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

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);

Затем вместо того, чтобы удерживать коллекцию IDomainEvent s, удерживайте коллекцию IEventRecords, в которой хранятся данные нужного типа, чтобы поднять себя:

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