Question

I have an interesting use case where certain exception types mean "This message is no longer valid and should be ignored" but this code doesn't have any awareness of the Bus in order to call Bus.DoNotContinueDispatchingCurrentMessageToHandlers().

I loathe boilerplate code like try/catch blocks that need to be present in every single message handler. So I started implementing a UnitOfWork to handle and swallow the exception, but I can't find a way to tell the framework that "Yes, this code generated an exception, but forget about that and just complete the transaction."

Bus.DoNotContinueDispatchingCurrentMessageToHandlers() does not work. I tried having an ITransport injected and calling AbortHandlingCurrentMessage() but that caused the entire universe to blow up. Even stepping through the source code I seem to be at a loss.

Note that it very well may be that this is a horrible idea, because faking that there is no exception when there is in fact an exceptional case would cause the transaction to commit, causing who knows how many bad unknown side effects. So it would be preferable to have a method that still rolls back the transaction but discards the message. But I would be interested in a potential "Yes I know what I'm doing, commit the transaction regardless of the exception" option as well.

Was it helpful?

Solution

As of NServiceBus version 4.4 you can control this by injecting a behavior into our handler pipeline.

This let's you control which exceptions to mute.

class MyExceptionFilteringBehavior : IBehavior<HandlerInvocationContext>
{
    public void Invoke(HandlerInvocationContext context, Action next)
    {
        try
        {
            //invoke the handler/rest of the pipeline
            next();
        }
        //catch specific exceptions or
        catch (Exception ex)
        {
            //modify this to your liking
            if (ex.Message == "Lets filter on this text")
                return;

            throw;
        }
    }

There are several samples of how this works:

http://docs.particular.net/samples/pipeline/

That said I totally agree with Ramon that this trick should only be used if you can't change to design to avoid this.

OTHER TIPS

A dirty solution would be having a unit of work test the exception, put the message id in a shared 'ignore' bag (concurrent dictionary in memory, db, what works for you) , let it fail so that everything is rolled back, in the retry have a generic message handler compare the message ID and let that call Bus.DoNotContinueDispatchingCurrentMessageToHandlers()

If you do not want to work with a unit of work then you could try to use the AppDomain.FirstChanceException.

I wouldn't advice any of these as good solution :-)

Why would you like to 'swallow' unhandled exceptions?

If you want to ignore an exception then you should catch these in the handler and then just return and log this.

What I'm more interested in is what about state? You maybe have already writen to a store. Shouldn't these writes be rolled back? If you swallow an exception the transaction commits.

It seems to me you are running in a kind of 'at least once delivery' environment. THen you need to store some kind of message id somewhere.

Or is it an action initiated by several actors based on a stale state? In that case you need to have first/last write wins construction that just ignores a command based on a stale item.

If you handl an event then swallowing a exception seems not correct. They usually say that you can ignore commands but that you always have to handle events.

Shouldn't this be part of validation? If you validate a command then you can decide to ignore it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top