Use generic decorators conditionally in Autofac based on type constraints

I have a request / handler based architecture app . I have the following interface:

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

There are many non-general implementations of this interface. These implementations are wrapped by universal decorators for registration, profiling, authorization, etc. Sometimes, however, I want to apply a common decorator conditionally based on the constraints of a typical decorator type. Take, for example, this caching decoder, which can only be applied to queries that return ReadOnlyCollection<T>(simply because caching any collection that is modified does not make much sense):

public class CachingQueryHandlerDecorator<TQuery, TResult> 
    : IQueryHandler<TQuery, ReadOnlyCollection<TResult>>
    where TQuery : IQuery<ReadOnlyCollection<TResult>>
{
    private readonly IQueryHandler<TQuery, ReadOnlyCollection<TResult>> decoratee;
    private readonly IQueryCache cache;

    public CachingQueryHandlerDecorator(
        IQueryHandler<TQuery, ReadOnlyCollection<TResult>> decoratee,
        IQueryCache cache)
    {
        this.decoratee = decoratee;
        this.cache = cache;
    }

    public ReadOnlyCollection<TResult> Handle(TQuery query)
    {
        ReadOnlyCollection<TResult> result;

        if (!this.cache.TryGetResult(query, out result))
        {
            this.cache.Store(query, result = this.decoratee.Handle(query));
        }

        return result;
    }
}

, , . . , CachingQueryHandlerDecorator ProfilingQueryHandlerDecorator SecurityQueryHandlerDecorator.

, ; , . Autofac?

+3
1

, , :

// Think of this as the "master decorator" - all calling code comes through here.
class QueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
    private readonly IComponentContext context;

    public QueryHandler(IComponentContext context)
    {
        this.context = context;
    }

    public TResult Handle(TQuery query)
    {
        var handler = context.Resolve<IQueryHandler<TQuery, TResult>>();

        if (typeof(TResult).IsClosedTypeOf(typeof(ReadOnlyCollection<>)))
        {
            // manual decoration:
            handler = new CachingQueryHandlerDecorator<TQuery, TResult>(handler);

            // or, container-assisted decoration:
            var decoratorFactory = context.Resolve<Func<IQueryHandler<TQuery, TResult>, CachingQueryHandlerDecorator<TQuery, TResult>>>();
            handler = decoratorFactory(handler);
        }

        if (NeedsAuthorization(query)) { ... }

        return handler.Handle(query);
    }
}

, , , . DI, , , .

, , , . , -, , .

, , QueryHandler IQueryHandler - . , Decorator " " , . , IQueryHandler , DI - , . " " " -" (. " Raiser" ) - .

-1

Source: https://habr.com/ru/post/1538848/


All Articles