I开发者_StackOverflow'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
isnull
. 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 doesbus.Return(errorCode)
. Are there other ways I can do that?
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>>();
}
}
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);
}
}
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.
精彩评论