Autofac根据构造函数参数名称按惯例获取装饰QueryHandler?

时间:2013-09-27 13:36:56

标签: asp.net-mvc dependency-injection inversion-of-control decorator autofac

我们将IQueryHandler<TQUery,TResult>注入我们的MVC控制器。我们在容器中全局注册所有这些

我们编写了一个可以缓存IQueryHandler

结果的装饰器

我们希望有时得到缓存的结果,而有时则不是来自同一个处理程序。

是否可以根据构造函数参数的名称有条件地获取修饰处理程序。例如注入IQueryHandler<UnemployedQuery, IEnumerable<People>> cachedPeopleHandler如果我们在构造函数参数名称前加上缓存,我们实际上是用decorator包装的吗?

尝试使用更多约定优于配置方法来简化操作。

1 个答案:

答案 0 :(得分:2)

是的,可以这样做。下面是一个简单的工作示例,说明如何实现它:

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();
        }

    }
}

<强>更新
基本上你需要:
1.想一个大会。在您的情况下为ctor参数名称添加“缓存” 2.像往常一样注册您的依赖项 3.注册装饰器,这样它们就不会覆盖原始依赖项,您可以根据惯例轻松解决它们。例如键控,命名,通过属性等。
注册你使用装饰器的类的实际实现 5.通过内部具有所有魔法的lambda表达式注册描述该类的接口。

注意:我提供了一个简单而有效的例子。让它变得美观,易于使用和快速,例如将它作为扩展,通用,缓存反射结果等。无论如何,这并不困难 感谢。