0

TL;DR コントラクト サブスクリプションでは、動的プロキシではなく、生のメッセージ コンテンツまたは元の公開オブジェクトを取得するにはどうすればよいですか?

MassTransit に基づいてモジュラー アプリケーションを作成しようとして、うまくいきません。

私の考えは、Websocket サーバーをキューに接続し、ソケットからイベントを読み取り、「接続要求」としてキューに挿入し、キューからイベントを読み取り、「接続イベント」としてソケットに送信することです。両方とも、WS サーバーがイベントの送信先の接続と、システムの残りの部分の送信元を認識できるようにするコントラクトがあります。

public interface IConnectionRequest
{
    String ConnectionId { get; set; }
}

public interface IConnectionEvent
{
    String ConnectionId { get; set; }
}

セッションやその他のデータを維持するオブジェクトがあります。このオブジェクトは、リクエスト (アクション リクエストやサブスクリプション リクエストなど) を受け入れ、リクエストの結果として、または単に状態が変化したためにイベントをプッシュします。特定のイベントまたは一連のイベントをリッスンし、状態に対してアクションを実行するオブジェクトを作成したいので、次のコントラクトを作成しました。

public interface IConnectionRequestHandler<T> : Consumes<T>.Selected
    where T : class, IConnectionRequest
{
}

たとえば、サーバーで実際のセッションを作成し、セッションの準備ができたときに通知する接続に応答するハンドラーを作成したいと考えています。リクエストを表すオブジェクトを作成し、その他のイベントとハンドラー自体を作成します。

public class CreateSessionRequest : IConnectionRequest
{
    public String ConnectionId { get; set; }
}

public class CreatedSessionEvent : IConnectionEvent
{
    public String ConnectionId { get; set; }
    public Guid SessionId { get; set; }
}

public class CreateSessionEventHandler : IConnectionRequestHandler<CreateSessionRequest>
{
    IServiceBus _bus;

    public CreateSessionEventHandler(IServiceBus bus)
    {
        _bus = bus;
    }

    public bool Accept(CreateSessionRequest message)
    {
        return true;
    }

    public void Consume(CreateSessionRequest message)
    {
        // do stuff, create the session
        var evt = new CreatedSessionEvent() { SessionId =Guid.NewGuid(), ConnectionId = message.ConnectionId };
        _bus.Publish(evt, evt.GetType());
    }
}

ここで、テスト目的で、シナリオをエミュレートする次のコードを作成します。基本的に、通信バスを作成し、リクエスト ハンドラをサブスクライブします。

var bus = ServiceBusFactory.New(sbc =>
{
    sbc.ReceiveFrom("loopback://localhost/queue");
});

bus.SubscribeInstance<CreateSessionEventHandler>(new CreateSessionEventHandler(bus));

次に、Websocket サーバーをシミュレートして、WS から読み取ってキューに送信する部分を作成します。

IConnectionRequest e = new CreateSessionRequest() { ConnectionId = "myId" };
bus.Publish(e, e.GetType());

そして、キューからイベントを受信し、適切な接続に転送することになっている部分:

bus.SubscribeHandler<IConnectionEvent>(evt => Console.WriteLine("Sending event '{0}' to connection: {1}",
                                                                evt.GetType().Name,  
                                                                evt.ConnectionId));

しかし、この最後の部分は期待どおりに機能しません。サブスクリプションで取得したオブジェクトは元のイベントではなく、動的なプロキシDynamicImpl.IConnectionEventであるため、のメンバーのみが含まれるため、このオブジェクトを JSON でシリアル化できませんIConnectionEvent

サブスクリプションでタイプを指定すると、次のように機能します。

bus.SubscribeHandler<CreatedSessionEvent>(evt => Console.WriteLine("Sending event '{0}' to connection: {1}",
                                                                evt.GetType().FullName,  
                                                                evt.ConnectionId));

しかし、新しいイベントごとに、Websocket サーバーにアクセスしてその新しいタイプを登録する必要があることを意味します。

これを回避する方法はありますか?

4

1 に答える 1

1

TL;DR - MT は、ほとんどのシリアル化のコントラクトのデータのみをサポートします。これには多くの理由がありますが、非プロキシ タイプが必要な場合は、バイナリ シリアライザーを使用する必要があります。

そのため、XML と JSON のシリアライゼーション (XML は実際にはフードの下で JSON シリアライザーを使用するだけで、奇妙なことに高速です) 可能であれば、すべてのリクエストに対してプロキシを生成します。サブスクライブ型は、使用しているコントラクトであり、コントラクトにない詳細についてオブジェクトに問い合わせることを期待しているため、非常に複雑になります。これは避けることをお勧めします。

つまり、消費することが予想されるメッセージの種類ごとに Websocket サーバーにアクセスする必要があります。あなたがしているのはメッセージの転送だけである場合、誰かが行った SingalR バックプレーン ( https://github.com/mdevilliers/SignalR.RabbitMqだと思います) があり、MT コンシューマーよりも適している可能性があります。

于 2014-08-20T14:47:45.990 に答える