The Inquisitive Coder – Davy Brion's Blog

Trying to walk that thin line between intelligence and ignorance

Batching WCF calls, Take 2

Posted by Davy Brion on July 1st, 2008

Update: i also have a complete series of posts on this which you may find interesting.

The first take was pretty good, after all it got Ayende-d which is the highlight of my blogging career so far :) . In his post, he was pretty positive about my implementation, with one small exception:


“About the only thing that I would strive to improve there would be the need to explicitly register request & replies. I would try to get something convention based there. Maybe something like Request, and then have IHandler and route the whole thing through the container again.”

Let’s give that a shot :)

Previously, the base implementation of the service routed the call to the correct RequestHandler like this:

        public Response[] Process(params Request[] requests)

        {

            if (requests == null)

            {

                return null;

            }

 

            var responses = new List<Response>(requests.Length);

 

            foreach (var request in requests)

            {

                Type handlerType = GetHandlerTypeFor(request);

 

                if (handlerType == null)

                {

                    responses.Add(new UnsupportedRequestResponse());

                    continue;

                }

 

                using (var handler = GetHandlerInstance(handlerType))

                {

                    responses.Add(handler.Handle(request));

                }

            }

 

            return responses.ToArray();

        }

 

        public virtual IRequestHandler GetHandlerInstance(Type handlerType)

        {

            return (IRequestHandler)Container.Resolve(handlerType);

        }

 

        public abstract Type GetHandlerTypeFor(Request request);

And then the service implementation would provide an implementation of the GetHandlerTypeFor method. In that implementation, you somehow had to map the type of the incoming Request to a handler. In the code that i posted i used a dictionary-based approach. You could’ve used a couple of if statements as well. The point is that you had to do that mapping which is indeed somewhat annoying.

First, we’ll add a new interface on top of the IRequestHandler interface:

    public interface IRequestHandler : IDisposable

    {

        Response Handle(Request request);

    }

 

    public interface IRequestHandler<TRequest> : IRequestHandler

        where TRequest : Request

    {

        Response Handle(TRequest request);

    }

We also modify the base RequestHandler class to provide a derived generic class:

    public abstract class RequestHandler : Disposable

    {

        protected IUnitOfWork UnitOfWork { get; private set; }

 

        protected RequestHandler(IUnitOfWork unitOfWork)

        {

            UnitOfWork = unitOfWork;

        }

 

        protected override void DisposeObjects()

        {

            if (UnitOfWork != null) UnitOfWork.Dispose();

        }

 

        protected override void ClearReferences()

        {

            UnitOfWork = null;

        }

    }

 

    public abstract class RequestHandler<TRequest> : RequestHandler, IRequestHandler<TRequest>

        where TRequest : Request

    {

        protected RequestHandler(IUnitOfWork unitOfWork) : base(unitOfWork) {}

 

        public abstract Response Handle(TRequest request);

 

        public Response Handle(Request request)

        {

            return Handle((TRequest)request);

        }

    }

The only reason why i still have the base RequestHandler type is to make it easier to register the RequestHandler types with the container (which i’ll show below).

A specific RequestHandler can now be defined like this:

    public class GetProductCategoriesHandler : RequestHandler<GetProductCategoriesRequest>

Right, now we can register all of our RequestHandler types with the container:

        private static void RegisterRequestHandlers()

        {

            foreach (var type in typeof(RequestHandler).Assembly.GetTypes())

            {

                if (type.IsSubclassOf(typeof(RequestHandler)) && type.BaseType.IsGenericType)

                {

                    var serviceType = typeof(IRequestHandler<>).MakeGenericType(type.BaseType.GetGenericArguments());

                    Register(Component.For(serviceType).ImplementedBy(type).LifeStyle.Transient);

                }

            }

        }

So now each generic RequestHandler type is registered through the generic IRequestHandler type.

Our base Service implementation now looks like this:

        public Response[] Process(params Request[] requests)

        {

            if (requests == null)

            {

                return null;

            }

 

            var responses = new List<Response>(requests.Length);

 

            foreach (var request in requests)

            {

                Type handlerType = typeof(IRequestHandler<>).MakeGenericType(request.GetType());

 

                using (var handler = (IRequestHandler)Container.Resolve(handlerType))

                {

                    responses.Add(handler.Handle(request));

                }

            }

 

            return responses.ToArray();

        }

And now you no longer need to map the Request type to the RequestHandler type yourself since the container now takes care of that for us.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>