Alexa .NET – Handlers and Interceptors

I think I may genuinely be running out of packages to write for the .NET Alexa community, but this one was important I got finished before I looked for my next project (I’ve not developed an actual skill in some time – it’s been all about the NuGet packages recently!)

One of the best things about the ASK SDK that the Alexa team produced is Handlers & Interceptors because when you’re trying to handle complex skills you spend a lot of time trying to ensure clean code, and the more you build up your dialogs the more complicated that seperation can become. Well – I felt .NET developers could use a similar set of structures to enable them to speed up clean development, so I wrote Alexa.NET.RequestHandlers which allows for several key concepts, which is what the rest of this article is going to show.

Request Handlers

Request Handlers are the first thing you’ll look at implementing once you’ve added the package to your project. Here’s the structure of each handler:

    public interface IRequestHandler
    {
          bool CanHandle(RequestInformation request);
          Task<SkillResponse> Handle(RequestInformation request);
    }
}

The idea is that each handler class handles requests that match a particular criteria (a specific request type, a specific intent, an intent that has certain slots filled etc.)

Which requests you want the handler to handle is indicated by the CanHandle method. The request picks the first handler to return true, so it’s best they’re added to the request object going from most to least specific.

public class IntentHandler: IRequestHandler{
   public bool CanHandle(SkillInformation information){
       return information.SkillRequest.Request is IntentRequest;
     }

     public Task<SkillResponse>(SkillInformation information)
     {
       return Task.FromResult(ResponseBuilder.Tell("Handler Found"));
     }
}
...
var intentHandler = new IntentHandler();
var request = new Request(new[]{intentHandler});
var response = request.Process(skillRequest);

What’s the RequestInformation object?

RequestInformation is an object used to allow several pieces of data to be sent through to the selected handler (and all the interceptors, we’ll get to that later).

RequestInformation contains:
SkillRequest: The main skill request
Context: An object passed into the process method, for a Lambda this could be the ILambdaContext object. request.Process(skillRequest, context);
Items: A dictionary of objects to be used between handlers and interceptors.

Error Handlers

Error handlers help you deal with specific exception situations, while still giving your users a conversational response. Their syntax is the same as Request Handlers, except they also pass in the exception that caused them to be found.

public interface IErrorHandler
{
  bool CanHandle(RequestInformation request, Exception exception);
  Task<SkillResponse> Handle(RequestInformation request, Exception exception);      
}

And they work the same way – the first error handler that returns true will be used to process the skill request/exception combination and still return a Skill Response.

If there are no request handlers available to handle the request being sent through, then the request throws a RequestHandlerNotFoundException – which can be picked up by an exception handler.

It’s worth noting that if there’s no matching Exception Handler, the request will just throw the exception so it can go up the stack as it would normally.

Interceptors

So the Request and Exception handlers are great for isolating logic into specific classes. But what if you want certain logic to be run regardless of which handler is selected? For example, if you want to always log the request coming in, or ensure that session information is always stored before going out? That’s where interceptors come in.

public interface IRequestHandlerInterceptor
{
  Task<SkillResponse> Intercept(RequestInformation info, RequestInterceptorCall next);
}

Interceptors are run in the order that they’re added to the request, each one having the ability to run code before and after the next one is executed – or possibly not even getting as far as running the handler! Again, the only difference between request handlers and error handlers are that the exception is passed in with the RequestInformation.

  public async Task<SkillResponse> Intercept(RequestInformation info, RequestInterceptorCall next){
  log.Info("before handler executes");
  var response = await next(info);
    log.Info("after handler executes");
    return response;
}

Try using it

This is just a whistlestop of the way this fits together, as the package itself is quite new and I don’t want to add too much without feedback – so please give it a try and let me know what you think.

Leave a Reply

Your email address will not be published. Required fields are marked *