RequestHandlerInterceptors

bartdeleye edited this page Jul 13, 2011 · 2 revisions

Introduction

One way to deal with cross-cutting concerns in Agatha is to subclass the RequestHandler base class. However, when applying a lot of different concerns that apply to different subsets of requests, you'll quickly and up with lots of base classes. A new way to deal with cross-cutting concerns in Agatha 1.3 is using request handler interceptors.

What

By implementing an interceptor you'll be able to intercept requests before or after they are processed by the registered RequestHandler.
Before the handler is invoked an interceptor can mark a request as processed, so it doesn't get processed by the handler anymore.
Multiple interceptors can be configured an will be invoked in the order of registration. Marking a request as processed, also skips all subsequent interceptors.

How

We'll guide you through the necessary steps by creating an interceptor that will validate each request.
You can find the code in the example projects Sample.ServiceLayer and Sample.ServiceAndClientInSameProcess

An interceptor should implement the following interface:

	public interface IRequestHandlerInterceptor : IDisposable
	    {
		void BeforeHandlingRequest(RequestProcessingContext context);
		void AfterHandlingRequest(RequestProcessingContext context);
	    }

Note the parameter of type RequestProcessingContext. Each interceptor lives during the scope of processing a single request.
The context also contains the response for the request to return to the client.
To intercept the processing of a request and return a response, call the MarkAsProcessed(Response response) method.
All further processing will be interrupted (subsequent interceptors and RequestHandler).
However, the AfterHandlingRequest will still be called for all invoked interceptors.

Here's an example of an interceptor:

	public class ValidatingInterceptor : ConventionBasedInterceptor
	    {
		public override void BeforeHandlingRequest(RequestProcessingContext context)
		{
		    try
		    {
		        Validate.Object(context.Request as dynamic);
		    }
		    catch (ValidationException exc)
		    {
		        var response = CreateDefaultResponseFor(context.Request);
		        response.Exception = new ExceptionInfo(exc);
		        response.ExceptionType = ExceptionType.Unknown;
		        context.MarkAsProcessed(response);
		    }
		}

		public override void AfterHandlingRequest(RequestProcessingContext context)
		{
		}

		protected override void DisposeManagedResources()
		{
		}
	    }

Ignore the base class for now, that will be explained later.
Before each request is handled, we'll try to validate it. If validation fails, a response will be returned with the validation exception.

Next, the interceptor should be registered in Agatha:

new ServiceLayerConfiguration(typeof(HelloWorldHandler).Assembly, typeof(HelloWorldRequest).Assembly, new Agatha.StructureMap.Container(ObjectFactory.Container))
            .RegisterRequestHandlerInterceptor<ValidatingInterceptor>()

This way you can separate each concern in a different class. In order to have the interceptor applied only for a subset of requests, check the request type (based on a superclass, marker interface, namespace, ....) before and/or after handling a request.

There is one issue left though, you cannot always know which Response type should be returned. This can be solved by another new feature in Agatha 1.3: Conventions.
A base interceptor class is provided to facilitate the creation of a response based on those conventions.

Furthermore we have some real-life examples on this page.