4

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?
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
keepitstupid
  • 63
  • 1
  • 5

3 Answers3

7

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>>();
     }
}
Simon
  • 33,714
  • 21
  • 133
  • 202
Udi Dahan
  • 11,932
  • 1
  • 27
  • 35
  • Excellent, I had searched through the documentation contents, but not the FAQ. May I ask what your opinion is on the best way to do user authentication? As I see it, I have three options: multiple message handlers (what this question is about), the `IMessageModule` as suggested by David (which gave me some trouble) or the wrapper as suggested by Adam Fyles (which I haven't tried yet). It would seem that multiple handlers has some overhead to it. – JulianR Nov 04 '10 at 19:24
  • NServiceBus by default sets the Windows Identity of the thread to that of the domain user who sent the message - this is called impersonation. Once you have that, you can authenticate based on that data. If you're looking for authorization, then look at including claims in the headers sent along with a message. – Udi Dahan Nov 04 '10 at 20:34
  • I've looked at the source, and it seems the `First` class really is just a neat way to construct a list of `Type`s. I'd like to do that myself and pass it in, but how would I do that? – Neil Barnwell Mar 01 '13 at 14:19
  • @NeilBarnwell we don't currently support that - but would welcome a pull request :) – Udi Dahan Mar 01 '13 at 14:48
  • Sure I'll take a look. Seems like just making `ConfigUnicastBus.LoadMessageHandlers(IEnumerable orderedTypes)` public, tbh? – Neil Barnwell Mar 01 '13 at 17:10
  • Do you have to put every single handler in that list or just the ones that require some sort of ordering? – Tim Burkhart Dec 03 '14 at 20:12
  • The First class is very difficult to work with. It makes using reflection to configure much more difficult. It's basically a misuse of generics to create a list of types. Overly complicated and causes me no end of pain. – Sprague May 09 '16 at 12:13
  • @Sprague see the bottom section of the documentation which shows the use of standard types: http://docs.particular.net/nservicebus/handlers/handler-ordering#with-the-configuration-api-specifying-multiple-to-run-ordered – Udi Dahan May 12 '16 at 07:03
4

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

    }
}
Adam Fyles
  • 6,030
  • 1
  • 23
  • 29
3

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.

David Boike
  • 18,545
  • 7
  • 59
  • 94