Autofac get decorated QueryHandler by convention based on constructor parameter name?

后端 未结 1 709
陌清茗
陌清茗 2021-01-25 13:23

We inject IQueryHandler into our MVC controllers. We globally register all of these in the container

We have written a decorator that

相关标签:
1条回答
  • 2021-01-25 14:28

    Yes it's possible to do it. Below is a simple working example on how you can achieve it:

    class Program
    {
        public interface IQueryHandler{}
    
        private class QueryHandler : IQueryHandler
        {
        }
    
        private class CacheQueryHandler : IQueryHandler
        {
        }
    
        public interface IService
        {
        }
    
        private class Service : IService
        {
            private readonly IQueryHandler _queryHandler;
            private readonly IQueryHandler _cacheQueryHandler;
    
            public Service(IQueryHandler queryHandler, IQueryHandler cacheQueryHandler)
            {
                _queryHandler = queryHandler;
                _cacheQueryHandler = cacheQueryHandler;
            }
    
            public override string ToString()
            {
                return string.Format("_queryHandler is {0}; _cacheQueryHandler is {1}", _queryHandler,
                    _cacheQueryHandler);
            }
        }
    
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            // Register the dependency
            builder.RegisterType<QueryHandler>().As<IQueryHandler>();
            // Register the decorator of the dependency
            builder.RegisterType<CacheQueryHandler>().Keyed<IQueryHandler>("cache");
    
            // Register the service implementation
            builder.RegisterType<Service>().AsSelf();
    
            // Register the interface of the service
            builder.Register(c =>
            {
                var ctor = typeof (Service).GetConstructors()[0];
    
                var parameters =
                    ctor.GetParameters()
                        .Where(p => p.Name.StartsWith("cache"))
                        .Select(p => new NamedParameter(p.Name, c.ResolveKeyed("cache", p.ParameterType)));
    
                return c.Resolve<Service>(parameters);
            }).As<IService>();
    
            using (var container = builder.Build())
            {
                var service = container.Resolve<IService>();
                Console.WriteLine(service.ToString());
    
                Console.ReadKey();
            }
    
        }
    }
    

    Update:
    Basically you need to:
    1. Think up a general convention. Prefix "cache" of ctor parameter name in your case.
    2. Register your dependencies as usual.
    3. Register your decorators, so they don't overwrite your original dependencies and you can easily resolve them basing on your convention. e.g. Keyed, Named, via Attribute, etc.
    4. Register you actual implementation of class that uses decorators
    5. Register your interface that describes the class via lambda expression that has all magic inside.

    Note: I provided just a simple and working example. It's on you to make it nice, easy to use and fast e.g. make it as an extension, generic, cache reflection results etc. It's not difficult anyway.
    Thanks.

    0 讨论(0)
提交回复
热议问题