This project is read-only.

Marker Interface collections and Decorators

Dec 30, 2014 at 9:38 AM
Can someone please advise on how to do correct registration for the following scenario

public abstract class Request{}

interface IHandler {
Object Handle(Request request);;
}

abstract class Handler<TRequest> : IHandler {
public abstract void Handle(TRquest request);

public void Handle(Request request){
    Hadnle(TRequest requet);
}
}

public class AddRequest : Request{}
public class AddHandler : Handler<AddRequest>{
public override Handle(AddRequest request){}
}

public class UpdateRequest ; Request{}
public class UpdateHandler : Handler<UpdateRequest>{
public override Handle(UpdateRequest request){}
}

public class LoggHandlerDecorator<TRequest> : Handler<TRequest>{
Handler<TRequest> _Decoratee;

public LoggHandlerDecorator(Handler<TRequest> decoratee){
    _Decoratee = decoratee;
}

public override void Handle(TRequest request){
    _Decoratee.Handle(request);
} 
}

class RequestDispatcher{
List<IHandlers> _Handlers;

public RequestDispatcher(IEnumerable<IHandler> handlers){
    _Handlers = handlers.ToList();
} 

public void Dispatch(Request request){
    _Handlers.ForEach(h => h.Handle(request))
}
}

Many thanks
Coordinator
Dec 30, 2014 at 10:09 AM
Edited Dec 30, 2014 at 10:11 AM
Hi,

Can you give a brief summary of what it is you are trying to do? The code you have put here does not compile.

Also, more specifically what is RequestDispatcher doing?
public class RequestDispatcher
{
    List<IHandler> _Handlers;

    public RequestDispatcher(IEnumerable<IHandler> handlers)
    {
        _Handlers = handlers.ToList();
    }

    public void Dispatch(Request request)
    {
        _Handlers.ForEach(h => h.Handle(request));
    }
}
Either Request is an Add or an Update and would never need to call multiple Handler's.

Handler<TRequest> does not implement IHandler
public interface IHandler
{
    Object Handle(Request request);
}

public abstract class Handler<TRequest> : IHandler
{
    public abstract void Handle(TRequest request);
}
Coordinator
Dec 30, 2014 at 10:15 AM
Edited Dec 30, 2014 at 10:19 AM
This dispatcher would make more sense:
public class RequestDispatcher2
{
    private readonly Container container;

    public RequestDispatcher2(Container container)
    {
        this.container = container;
    }

    public void Dispatch<TRequest>(TRequest request) where TRequest : Request
    {
        this.container.GetInstance<Handler<TRequest>>().Handle(request);
    }
}
do away with IHandler and configure the container:
var container = new Container();
container.RegisterManyForOpenGeneric(typeof(Handler<>), typeof(Handler<>).Assembly);
container.RegisterDecorator(typeof(Handler<>), typeof(LogHandlerDecorator<>));
container.Register<RequestDispatcher2>();
container.Verify();

var dispatcher = container.GetInstance<RequestDispatcher2>();
dispatcher.Dispatch(new AddRequest());
Coordinator
Dec 30, 2014 at 10:19 AM
Take a look at this article, I think it describes exactly what you need:

https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91
Dec 30, 2014 at 5:20 PM
Edited Dec 30, 2014 at 5:22 PM
@qujck, @dot_NET_Junkie

Thanks for your quick replies.

Yes I have seen this approach before, but do not like the dependency on the container inside my framework code. My DI provider is abstracted as a Common Service Locator in a separate assembly from the CQS infrastructure code and Injecting the Container into RequestDispatcher means a dependency on SimpleInjector.

Also injecting IHandler keeps the intent and requirement of the Dispatcher clear.

I nearly got this working with the following registration.
Container.RegisterAll(
    typeof(IHandler), 
    commandHandlerAssembly
);

Container.RegisterDecorator(
    typeof(IHandler),
    _ => typeof(LogHandlerDecorator<>).MakeGeneric(_.ImplementationType.BaseType.GetGenericArguments()),
    Lifestyle.Singleton
    _ => true
);
I have confirmed that the Decorator delegate does trigger returning the constructed generic and the collection injected into Dispatcher appears to contain elements , however as soon as an attempt is made to the enumerate the collection I get "Sequence contains no elements" exception
Coordinator
Dec 30, 2014 at 5:59 PM
What about this?
public class RequestDispatcher3
{
    private readonly Func<Type, object> handlerFactory;

    public RequestDispatcher3(Func<Type, object> handlerFactory)
    {
        this.handlerFactory = handlerFactory;
    }

    public void Dispatch<TRequest>(TRequest request) where TRequest : Request
    {
        var handler = this.handlerFactory(typeof(Handler<TRequest>);
        (handler as Handler<TRequest>).Handle(request);
    }
}
with this registration
var container = new Container();
container.RegisterManyForOpenGeneric(typeof(Handler<>), typeof(Handler<>).Assembly);
container.RegisterDecorator(typeof(Handler<>), typeof(LogHandlerDecorator<>));
container.RegisterSingle<Func<Type, object>>(type => container.GetInstance(type));
container.Register<RequestDispatcher3>();
container.Verify();

var dispatcher = container.GetInstance<RequestDispatcher3>();
dispatcher.Dispatch(new AddRequest());
Marked as answer by dot_NET_Junkie on 1/14/2015 at 2:17 AM
Coordinator
Dec 30, 2014 at 11:12 PM
Dependenies from your application code upon the container are problematic and must be prevented. That's why Service Locator is an anti-pattern. Your complete composition root however, is free to have as much dependencies on your container, without causing any maintainability issues and without applying Service Locator. This is explained clearly by Mark Seemann here: http://blog.ploeh.dk/2011/08/25/ServiceLocatorrolesvs.mechanics/

So the usual thing to do is to define an abstraction for your dispatcher in the application code and create an implementation of this abstraction in your com composition root; the startup path of your application.

This way you keep your application clean and free from the Service Locator anti-pattern, with its maintainability issues.
Jan 2, 2015 at 6:37 PM
Thanks @qujck !!

Yes Yes This is great and I should have seen it, guess I seem to loose common sense when staring at something for too long.

Gonna give it a go later in my implementation. However my actual implementation is a little more involve in that Handlers also have return types
Handler.

Does simple injector have a way to retrieve an instance based on the first type parameter or is it a question using reflection and iterating the registrations.

Alternatively I was thinking to create an container extension method for registration to keep a custom registry of each handler type by its TRequest type before registering it with the container, then a retrieval extension method to first get the appropriate handler type from this custom registry by the request type and using tis type to then get the actual Handler instance from the container.

Any thought ?

Many thanks again and Happy New Year !!
Coordinator
Jan 2, 2015 at 8:10 PM
Hi @ricardo100671, Happy New Year to you too!

Is it always the same return type? If not how do you know what return type to expect?
Jan 2, 2015 at 10:37 PM
@qujck

No the result are not always the same. Just as request all result derive from 'Result'. While Handlers return HandlerSpecificResult, Dispatcher returns the the 'Result' base. Clients will inspect the Result type and need to cast to access details of the specific result.

Typically Request and Results are compiled into their own assembly and distributed to clients or in a disconnected environment are exposed as, dynamically discovered, WCF Known Types
Coordinator
Jan 2, 2015 at 11:10 PM
Coordinator
Jan 2, 2015 at 11:19 PM
That's what I was going to say! The QueryProcessor in the first link looks like the solution you are seeking ....
Jan 13, 2015 at 8:06 AM
Thank guys

That has been a great help and I have made good progress. So the Dispatcher now looks like
public class RequestContractDispatcher : IContractDispatcher
{
        readonly Func<IContract, IHandler> _HandlerProvider;

        public RequestContractDispatcher(Func<IContract, IHandler> handlerProvider) {
            _HandlerProvider = handlerProvider;
        }

        public ResultContract Dispatch(RequestContract request) {
            return _HandlerProvider(request).Handle(adaptedRequest);
        }
}
Bearing in mind that I need to allow for multiple instances of a constructed request that will be filtered by a CanHandle override.
eg.
public class AddSpecialRequestHandler : Handler<AddRequestContract<NullResultContract>>
{
     public override CanHande(AddRequest request){
         return request.IsSpecial;
     }
}

public class AddStandardRequestHandler : Handler<AddRequestContract<NullResultContract>>
{
     public override CanHande(AddRequest request){
         return request.IsSpecial;
     }
}
I have done my registrations as follows
Container.RegisterSingleDecorator(typeof(Handler<,>), typeof(LoggingHandlerDecorator<,>));
Container.RegisterAllOpenGeneric(Handler<,>, dynamicallyDescoverTypes);
Container.RegisterSingle<Func<Type, object>>(t => {
     var typeOfRequestContract = t;
     var typeOfResultContract = typeOfRequestContract.BaseType.GetGenericArguments()[0];
     var handlerType = typeof(Handler<,>).MakeGenericType(typeOfRequestContract, typeOfResultContract);
    
      var handlers = container
           .GetAllInstances(handlerType)
           .Cast<IHandler>()
           .ToList();

       return handlers
            .Single(h => h.CanHandle(requestContract));
});
So i can verify that the handlers register correctly as an Enumeration and all works fine until I register the decorator, then I am getting
The registered delegate for type IEnumerable<Handler<RequestContract, ResultContract+NullResultContract>> threw an exception. Error occurred while trying to build a delegate for type IEnumerable<Handler<RequestContract, ResultContract+NullResultContract>> using the expression "value(SimpleInjector.Advanced.ContainerControlledCollection`1[Handler`2[RequestContract,ResultContract+NullResultContract]])". Thread was being aborted.
Strangely, whilst writing this and stepping though, on one occasion it all seemed to work and I got the expected two LoggingHandlers. for a moment i thought I had cracked it but then got the exceptions again.
Coordinator
Jan 13, 2015 at 8:19 AM
Would you be able to provide us with the minimum amount of code to reproduce this issue and the complete stack trace? And which version of Simple Injector are you using?
Jan 14, 2015 at 10:16 AM
Thank you. Looks like it was just a gremlin, after a little clean up the issues has dissipated. Working a treat.
Marked as answer by dot_NET_Junkie on 1/14/2015 at 2:17 AM