NServiceBus: specifying message order

2020-03-24 04:33发布

I'm using NServiceBus in it's own process (so not using the Generic Host) and I would like to have multiple message handlers for a message in a specific order. For the Generic Host, you would implement ISpecifyMessageHandlerOrdering, but I don't know how to do this when hosting your own NServiceBus process since that interface is defined in NServiceBus.Host.exe and I haven't been able to find another way to do this.

The purpose of this is user authentication: before the actual message handler is invoked, I would first like to authenticate the sender of the message, which would happen in a different, more generic, message handler. The message will be of a type that contains the encrypted user name and password and/or a session ID. This type will be used for almost all commands sent to the server (everything but login I think). Is this an OK way to do user authentication using NServiceBus?

Currently, it picks up the second handler but not in the right order.

Update

As suggested by David I tried creating a IMessageModule and reading the headers from the CurrentMessageContext to authenticate the user.

I ran into some problems here:

  • The first time I send a message, the bus.CurrentMessageContext is null. Every time after that, it's filled in correctly and I can read the headers.
  • Calling bus.DoNotContinueDispatchingCurrentMessageToHandlers when the user is not authenticated does not stop the message handlers from being invoked. Neither does bus.Return(errorCode). Are there other ways I can do that?

3条回答
够拽才男人
2楼-- · 2020-03-24 05:24

As described in the NServiceBus FAQ on the documentation page:

http://docs.particular.net/nservicebus/handlers/handler-ordering

How do I specify the order in which handlers are invoked?

If you're writing your own host:

NServiceBus.Configure.With()
 ...
 .UnicastBus()
      .LoadMessageHandlers(First<H1>.Then<H2>().AndThen<H3>().AndThen<H4>() //etc)
 ...

If you're using the generic host

public class EndpointConfig : IConfigureThisEndpoint, ISpecifyMessageHandlerOrdering
{
     public void SpecifyOrder(Order order)
     {
          order.Specify(First<H1>.Then<H2>().AndThen<H3>().AndThen<H4>() //etc);
     }
}

If you only want to specify a single handler (with your own host)

NServiceBus.Configure.With()
     ...
     .UnicastBus()
          .LoadMessageHandlers<FIRST<YourHandler>>()
     ...

If you only want to specify a single handler (with the generic host)

public class EndpointConfig : IConfigureThisEndpoint, ISpecifyMessageHandlerOrdering
{
     public void SpecifyOrder(Order order)
     {
          order.Specify<FIRST<YourHandler>>();
     }
}
查看更多
地球回转人心会变
3楼-- · 2020-03-24 05:31

Have you considered a message module for this purpose?

public interface IMessageModule
{
    // Methods
    void HandleBeginMessage();
    void HandleEndMessage();
    void HandleError();
}

Implementing this interface gives you a point to have code called before and after every message. If you inject an IBus, you can access the current message context, and from there inspect headers and use that to authenticate your messages.

查看更多
老娘就宠你
4楼-- · 2020-03-24 05:32

Another possibility would be to implement a base message handler class that would conditionally skip the handling based on your authentication check.

public abstract class MessageHandlerBase<T> : IMessageHandler<T> where T : IMessage
{
    public abstract void HandleMessage(T message);

    public void Handle(T message)
    {

        if (CredentialsValid(message))
            this.HandleMessage(message);

    }
}
查看更多
登录 后发表回答