4

まず、 'UserContext'を、ユーザーの正しいコンテキストで受信メッセージを実行するために必要ないくつかのプロパティとして定義しましょうstring。私の場合、これには、ユーザーが作業していたアプリケーションの「インスタンス」に関するデータも含まれます。

私が見ているように、メッセージに「UserContext」を提供するには2つの主なオプションがあります。

  1. ヘッダーとして
  2. メッセージの基本クラスとして

ヘッダーを使用する場合、独自のシリアライゼーションを提供する必要があります。基本クラスを使用する場合、Rebus がシリアライゼーションを解決してくれます。

そこで、小さなサンプル プログラムを使用して基本クラスを使用してスパイクしました。

public class UserContext
{
    public string Name { get; set; }

    public int UserId { get; set; }

    public Guid AppId { get; set; }
}

public class UserContextMessageBase
{
    public UserContext UserContext { get; set; }
}

public class SimpleMessage : UserContextMessageBase
{
    public string Data { get; set; }
}


internal class Program
{
    private static void Main(string[] args)
    {
        using (var adapter = new BuiltinContainerAdapter())
        using (var timer = new Timer())
        {
            //adapter.Register(typeof(UserContextHandler));
            adapter.Register(typeof(SimpleMessageHandler));

            var bus = Configure.With(adapter)
                               .Transport(t => t.UseMsmqAndGetInputQueueNameFromAppConfig())
                               .MessageOwnership(d => d.FromRebusConfigurationSection())

                               //.SpecifyOrderOfHandlers(o => o.First<UserContextHandler>())

                               .CreateBus()
                               .Start();

            timer.Elapsed += delegate
            {
                bus.Send(new Messages.SimpleMessage { Data = Guid.NewGuid().ToString() });
            };
            timer.Interval = 10000;
            timer.Start();

            Console.WriteLine("Press enter to quit");
            Console.ReadLine();
        }
    }
}

internal class UserContextHandler : IHandleMessages<UserContextMessageBase>
{
    protected UserContext _context;

    public void Handle(UserContextMessageBase message)
    {
        var old = Console.ForegroundColor;
        if (_context != null)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("Context is already populated");
        }

        Console.ForegroundColor = ConsoleColor.DarkYellow;
        Console.WriteLine("Processing UserContextMessageBase");
        // create the correct Context to process the message
        _context = message.UserContext;
        Console.ForegroundColor = old;
    }
}

internal class SimpleMessageHandler : **UserContextHandler**, IHandleMessages<SimpleMessage>
{
    public void Handle(SimpleMessage message)
    {
        // allow to use the _context to process this message
        Console.WriteLine("Received SimpleMessage {0}", message.Data);
    }
}

しかし、プログラムを実行すると、 が2 回SimpleMessage処理されていることがわかります。これは「設計による」ものですか、それともバグですか?

一方、 の登録のコメントを外してUserContextHandler、からを継承することはできませんが、 を に詰め込み、からそのまま使用する必要があります。SimpleMessageHandlerUserContextHandlerUserContextMessageContextSimpleMessageHandler

4

1 に答える 1

1

私の意見では、両方のアプローチが有効です-個人的には、ヘッダーはノイズが少ないため、ヘッダーを使用することに傾倒します:)しかし、あなたが正しく述べているように、それには何らかの形でユーザーコンテキストを1つ以上のヘッダーに「シリアライズ」し、各メッセージを受信するたびに再度デシリアライズします。

ヘッダー アプローチは非常にエレガントに実行できますが、メッセージ ハンドラーから離れて、それぞれ送信と受信のMessageSentおよびMessageContextEstablishedイベントで、ユーザー コンテキストをメッセージ コンテキストで使用できるようにすることができます。

メッセージ基本クラスを使用する他のアプローチも間違いなく有効です。着信メッセージのルックアップがルックアップごとに新しいハンドラー インスタンスを取得するという事実に見舞われていることがわかります。したがって、パイプラインには 2 つのものが含まれます。その後、メッセージは各ハンドラ インスタンスに「可能な限り」(つまり、互換性のあるタイプ/スーパータイプごとに 1 回) ディスパッチされるため、メッセージを効果的に 2 回処理することになります。

あなたの場合、最後に示唆するようにすることをお勧めします:パイプラインの最初になることを保証する別のハンドラーを作成し、後続のすべてのハンドラーが抽出UserContextHandlerできるようにユーザー コンテキストを格納できるようにします。MessageContext.GetCurrent().Items

ただし、必要なことを正確に行う方法を示す例を作成したいと思いますが、ヘッダーを使用します (;キーと値のペアの単純な区切りリスト、または同様のものの形式である可能性があります)。残念ながら、そのような例が数日以内に利用可能になるとは約束できません。

それがうまくいくかどうか教えてください:)

更新: Rebus のサンプル リポジトリにサンプルを追加しました。これは、構成と DI に関するいくつかの気の利いたものを含む、アンビエント ユーザー コンテキストを取得してメッセージ ヘッダーで渡す方法を示しています。これはUserContextHeadersと呼ばれます。チェックしてください :)

于 2014-03-18T13:56:39.403 に答える