5

最近のプロジェクトでイベンティングを実装するのに苦労しています。

structuremap が適切にスキャンされ、EventHandler がアセンブルされ、追加されていることを確認しました。

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

            }

        }

    }

ドメインからイベントを発生させる前に。のようなもの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

この質問をもっと注目させる方法がわかりません。希望する結果を達成するためのソリューションに報奨金を追加しています。質問が明確でない場合は、質問してください。

基本的に、 typeのwhere is のObjectFactory.GetAllInstances<IHandle<TEvent>>()ハンドラーを返すようにします。発生するイベントは Collection に格納され、Domain が (サービス層から) 保存された後に発生します。TEventTEventIDomainEventIDomainEvent

IDomainEvent発生したイベントが実際にタイプであることを構造マップに知らせる方法があるはずだと考えていますDomainEvent

var eventsToRaise=ディーラー.EventsToRaise(); デバッグ ウィンドウからの情報の追加:

ディスパッチャ ウィンドウでイベントが発生した後

ここに画像の説明を入力

編集 3: eventToRaise は「DealerName Changed」および「DealerCommunicationChanged」と表示されますが、
typeof(TEvent) は Type を Domain.IDomainEvent として指定します。

(VSウォッチウィンドウが情報を取得している場所から)正しいタイプにキャストできるようになることが可能であれば、問題は解決される可能性があると思います

- - - 結果 - -

どちらのアプローチも機能しました。私は両方を私のチームの他の 2 人のメンバーにアプローチしましたが、私たちは反射なしの解決策が正しい答えとして選択されると感じました。

今日は、実装を変更してテストを行い、ソリューションにこのソリューションに関する問題があるかどうかを確認します。

リフレクションベースのソリューションも正しい答えであるため、賛成票を投じました。


4

2 に答える 2

4

あなたが言うように、問題は、すべてのインスタンスに対して構造マップを要求IHandle<IDomainEvent>していて、それらのいずれも持たず、構造マップには具体的なイベントのハンドラーがあることです。イベントの実際の型を使用して型を構築し、そのイベントのすべてのハンドラーを要求する必要があります。

        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);
        }
于 2011-06-16T17:17:58.823 に答える
1

リフレクション ベースのアプローチではなく、レコードを使用して型情報を保持することをお勧めします。このようなもの:

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のコレクションを保持します。IEventRecords

foreach (var eventRecord in Records)
{
    eventRecord.Dispatch(myDispatcher);
}
于 2011-06-16T18:09:34.650 に答える