So far in this series, we have a basic command processor set up and able to dispose of resources. But what happens when things go wrong? The command processor has a fallback mechanism to handle exceptions that are not caught.
To add this functionality all you need to do is to decorate your handler with a fallback policy attribute, add the Fallback handler into your Dependency Injection framework, and then override the Fallback
method.
To add the Fallback handler to .NET Core’s Dependency Injection framework we add
serviceCollection.AddScoped(typeof(FallbackPolicyHandler<>));
to the BuildServiceProvider
method. The typeof
variant of AddScoped
allows a more general type to be expressed. Otherwise, we’d have to add a fallback policy handler for each command.
Our little salutation handler now looks like this:
[FallbackPolicy(backstop:true, circuitBreaker:false, step:1)] public override SalutationCommand Handle(SalutationCommand command) { Console.WriteLine($"Greetings, {command.Name}."); ThrowOnTheDarkLord(command); return base.Handle(command); }
(If you’ve not read Harry Potter, the reference is that if you use He-who-must-not-be-named’s name, then a death eater will appear and take you away. So if we use The Dark Lord’s name we’re throwing an exception)
Back to the code: The first line is the attribute decoration. In this case we say we have a fallback policy that acts as a backstop for any unhandled exception (backstop:true
). We’ve not covered the Circuit Breaker so we’re not interested in that for the moment (circuitBreaker:false
), and we’ve also not covered what happens if you have multiple attributes (step:1
) so we’ll leave that as step 1 (of 1). I’ll come back to those things later.
Now, if we put “Voldemort” in as the Name
in the command, it will throw an exception. So we have to handle that somehow. The RequestHandler
class has a Fallback
method which you can override in your derived handler class.
public override SalutationCommand Fallback(SalutationCommand command) { if (this.Context.Bag .ContainsKey(FallbackPolicyHandler<SalutationCommand> .CAUSE_OF_FALLBACK_EXCEPTION)) { Exception exception = (Exception)this.Context .Bag[FallbackPolicyHandler .CAUSE_OF_FALLBACK_EXCEPTION]; Console.WriteLine(exception); } return base.Fallback(command); }
What is happening here is that we are retrieving the Exception
from the Context
‘s Bag
, which is just a Dictionary
. Then we can do what we want with the Exception
. In this simple example, I’m just writing it to the console, but you’ll most likely want to do something more with it in your application.
As you can see, this is a bit on the clunky side, so where I’ve used Brighter before, I’ve tended to introduce a class between RequestHandler
and the specific handler to put in some things that help clean things up.
In this case the MyRequestHandler
class looks like this:
public class MyRequestHandler<TCommand> : RequestHandler<TCommand> where TCommand : class, IRequest { public override TCommand Fallback(TCommand command) { if (this.Context.Bag .ContainsKey(FallbackPolicyHandler .CAUSE_OF_FALLBACK_EXCEPTION)) { Exception exception = (Exception)this.Context .Bag[FallbackPolicyHandler .CAUSE_OF_FALLBACK_EXCEPTION]; return base.Fallback(ExceptionFallback(command, exception)); } return base.Fallback(command); } public virtual TCommand ExceptionFallback(TCommand command, Exception exception) { // If exceptions need to be handled, // this should be implemented in a derived class return command; } }
At the top we can see that instead of a specific command we still have the generic TCommand
, which needs to be a class
and derived from IRequest
. That wasn’t seen in the specific command handler because the explicit command already has these properties, so we didn’t need to express them again.
The Fallback
method now contains the code that extracts the exception from the Context
and calls ExceptionFallback
. In this class ExceptionFallback
does nothing except return the command back. When we implement it in our SalutationHandler
, the code for handling the exception now looks like this:
public override SalutationCommand ExceptionFallback(SalutationCommand command, Exception exception) { Console.WriteLine(exception); return base.ExceptionFallback(command, exception); }
And that is so much nicer to read. We’ve extracted away the plumbing of retrieving the exception to the newly introduced base class and our command handler looks much neater as a result.
To view the source as a whole, see it on GitHub.
3 Comments