The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

falthazar (7) [Avatar] Offline
#1
I'm using the query processor as described in your blog: https://cuttingedge.it/blogs/steven/pivot/entry.php?id=92

But since I need to have the query handler decorated, I can't use
container.GetInstance(handlerType)


I'm using EF core, and need to decorate the queries to be threadscoped (and later for logging). Is there another way to avoid constructor over-injection, while keeping the queries decorated?

Is there a simpler method for a query processor?

EDIT: Sorry, I forgot to list the actual error message and related code.

DynamicQueryProcessor:

    class DynamicQueryProcessor : IQueryProcessor
    {
        private readonly Container container;

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

        //[DebuggerStepThrough]
        public TResult Execute<TResult>(IQuery<TResult> query) {
            //query + query type?

            Func<Type, object> handlerFactory = container.GetInstance;
            
            Type handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));
            
            dynamic handler = this.container.GetInstance(handlerType);

            return handler.Handle((dynamic) query);
        }
    }


Error happens at:
dynamic handler = this.container.GetInstance(handlerType);

It is saying the DBContext is registered as threadscoped but the instance is requested outside the context of an active scope.

The bootstrapper for this layer is:
 public static void Bootstrap(Container container) {

            container.Register(typeof(ICommandHandler<>), typeof(ICommandHandler<>).Assembly);
            container.RegisterDecorator(typeof(ICommandHandler<>), typeof(SaveChangesCommandHandlerDecorator<>));
            container.RegisterDecorator(typeof(ICommandHandler<>), typeof(ThreadScopedCommandHandlerDecorator<>));

            container.RegisterSingleton<IQueryProcessor, DynamicQueryProcessor>();

            container.Register(typeof(IQueryHandler<,>), typeof(IQueryHandler<,>).Assembly);
            container.RegisterDecorator(typeof(IQueryHandler<,>), typeof(ThreadScopedQueryHandlerDecorator<,>));
        }



I am looking at your SolidServices code and I think it's essentially doing the same thing? But for some reason the query gets decorated, and mine does not and I can not figure out why.
Steven van Deursen (43) [Avatar] Offline
#2
Just wrap the resolve and execution of the query handler into a Scope:

public TResult Execute<TResult>(IQuery<TResult> query) {
    using (AsyncScopedLifestyle.BeginScope(this.container))
    {
        Type handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));
	         
        dynamic handler = this.container.GetInstance(handlerType);
	 
        return handler.Handle((dynamic) query);
    }
}


Or, you can start a scope on a different level; that's up to you. With the SOLID Services project, every request is wrapped in the scope of an AsyncScopedLifestyle. This ensures that during the time a query handler is resolved, there is an active scope that can be used to resolve scoped instances.
falthazar (7) [Avatar] Offline
#3
How would I decorate the queries later, if I wanted to later add logging or authentication?

Why isn't the query getting decorated with the thread scoped decorator?

When I ran Solid Services, container.GetInstance() did decorate the query with the AuthorizationQueryHandlerDecorator.
Steven van Deursen (43) [Avatar] Offline
#4
The handler should get decorated. Please make sure you are not resolving a concrete type, because in that case Simple Injector can't wrap a decorator. For instance:

var container = new Container();
container.Register<IService, Component>();
container.RegisterDecorator<IService, LogginDecorator>();

container.GetInstance<IService>(); // gets a decorated Component
container.GetInstance<Component>(); // gets Component directly. Impossible to wrap a decorator
falthazar (7) [Avatar] Offline
#5
When I go in and debug, handlerType:
Type handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));


Is:
IQueryHandler<QueryDto, IQueryable<QueryResult>>



That is what it should be, right?

Does it matter if I use container.GetInstance() vs container.GetInstance<>()
Steven van Deursen (43) [Avatar] Offline
#6
Consider the following small program:

using System;
using SimpleInjector;

// Abstractions
public interface IQuery<TResult> { }
public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
    TResult Handle(TQuery query);
}
public interface IQueryProcessor
{
    TResult Process<TResult>(IQuery<TResult> query);
}

// Messages
public class StudentDto { }
public class FindStudentsByName : IQuery<StudentDto[]>
{
    public string SearchText { get; set; }
}

// Implementations
public class FindStudentsByNameHandler : IQueryHandler<FindStudentsByName, StudentDto[]>
{
    public StudentDto[] Handle(FindStudentsByName query) => new StudentDto[0];
}

public class LoggingQueryHandlerDecorator<TQuery, TResult>
    : IQueryHandler<TQuery, TResult>
    where TQuery : IQuery<TResult>
{
    private readonly IQueryHandler<TQuery, TResult> decoratee;

    public LoggingQueryHandlerDecorator(IQueryHandler<TQuery, TResult> decoratee) 
        => this.decoratee = decoratee;

    public TResult Handle(TQuery query)
    {
        Console.WriteLine($"Handling {typeof(TQuery).Name}");
        return this.decoratee.Handle(query);
    }
}

public class Program
{
    static void Main(string[] args)
    {
        var container = new Container();

        IQueryProcessor processor = new QueryProcessor(container);
        container.Register(typeof(IQueryHandler<,>), typeof(FindStudentsByNameHandler).Assembly);
        container.RegisterDecorator(typeof(IQueryHandler<,>), typeof(LoggingQueryHandlerDecorator<,>));
        container.Verify();

        StudentDto[] result = processor.Process(new FindStudentsByName { SearchText = "Seemann" });

        Console.WriteLine("Number of found students: " + result.Length);
        Console.ReadLine();
    }

    sealed class QueryProcessor : IQueryProcessor
    {
        private readonly Container container;

        public QueryProcessor(Container container) => this.container = container;

        public TResult Process<TResult>(IQuery<TResult> query)
        {
            var handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));
            dynamic handler = container.GetInstance(handlerType);
            return handler.Handle((dynamic)query);
        }
    }
}


This program does the following:

  • * Defines one single query handler implementation (for searching students by their name

  • * Defines one decorator for query handlers

  • * Auto-registers all query handler that live in the same assembly as FindStudentsByNameHandler (means in this case only that handler is registered)

  • * Registers the decorator to be applied to all query handler abstractions.

  • * Sends a query message to the QueryProcessor.


  • When I run this example on my computer, the output of this program is:

    Handling FindStudentsByName
    Number of found students: 0
    


    There are two things you can do to find your problem:

  • * Either you use this example and add new code incrementally and run often to see wether it keeps working

  • * You reduce functionality of your own implementation in small steps and run often to see when it it starts working to find out where the problem is.
  • falthazar (7) [Avatar] Offline
    #7
    As always, thank you so much! I narrowed down the issue.

    It definitely was getting decorated, but I didn't realize that I only start the thread scope in the Handle method, not when the decorator is instantiated.

    I've changed it too:
        
    public class ThreadScopedQueryHandlerDecorator<TQuery, TResult> : IQueryHandler<TQuery, TResult>
            where TQuery : IQuery<TResult>
        {
            private readonly IQueryHandler<TQuery, TResult> decorated;
            private readonly Container container;
    
            public ThreadScopedQueryHandlerDecorator(IQueryHandler<TQuery, TResult> decorated, 
                                                     Container container) {
                this.decorated = decorated;
                this.container = container;
                ThreadScopedLifestyle.BeginScope(this.container);
            }
    
            public TResult Handle(TQuery query) {
                var result = this.decorated.Handle(query);
                Lifestyle.Scoped.GetCurrentScope(this.container).Dispose();
                return result;
            }
        }


    Though I'm not sure if that is the best method, since I call Dispose directly.
    Steven van Deursen (43) [Avatar] Offline
    #8
    Your current implementation is certainly not the best implementation. You should never start a scope in the constructor. The constructor should do nothing but storing incoming dependencies (as we explain in chapter 4).

    Besides, starting the scope at that point is too late, as the decorated handler has already been created. Instead, you should do the following:

    public class ThreadScopedQueryHandlerDecorator<TQuery, TResult> : IQueryHandler<TQuery, TResult>
        where TQuery : IQuery<TResult>
    {
        private readonly Func<IQueryHandler<TQuery, TResult>> decoratedFactory;
        private readonly Container container;
    
        public ThreadScopedQueryHandlerDecorator(
            Func<IQueryHandler<TQuery, TResult>> decoratedFactory,
            Container container) {
            this.decorated = decorated;
            this.container = container;
        }
    
        public TResult Handle(TQuery query) {
            using (ThreadScopedLifestyle.BeginScope(this.container)) {
                var decorated = this.decoratedFactory();
                return this.decorated.Handle(query);
            }
        }
    }
    


    This does a few things:

    * Instead of injecting the decorated handler, you inject a factory that will be able to create the decorated handler
    * When Handle is called a new Scope is started
    * Within that scope, the factory is invoked and the handler will be created.
    * When the method returns, the scope is disposed, and with it, all scoped dependencies created during that scope.

    Because both the Container and the factory are singletons, you can register this decorator as singleton as well, even though its decoratees aren't:

    container.RegisterDecorator(
        typeof(IQueryHandler<,>),
        typeof(ThreadScopedQueryHandlerDecorator<,>),
        Lifestyle.Singleton);
    


    You'll actually find an example of a very similar decorator in the Simple Injector documentation: https://simpleinjector.org/aop#decorators-with-func-t-decoratee-factories