autofac - 如何在Autofac中注册循环类型?

标签 autofac circular-dependency

我有一个存储库接口(interface)和类。我还有服务接口(interface)和类,它们依赖于存储库接口(interface)。典型的DI。我的目标是在服务和存储库之间添加缓存,而不是触及服务或存储库。这是代码:

public class CachedCustomerRepository : ICustomerRepository
{
    private readonly ICustomerRepository _repository;
    private readonly ConcurrentDictionary<int, Customer> _cache;

    public CachedCustomerRepository(ICustomerRepository repository)
    {
        if (repository == null)
            throw new ArgumentNullException("repository");

        this._repository = repository;
        this._cache = new ConcurrentDictionary<int, Customer>();
    }
}

我已经在温莎城堡做到了这一点。我刚刚添加了该类(class),它立即生效,没有任何注册更改。这对我来说真是哇的效果! :) 现在我尝试用 Autofac 做同样的事情,但失败了。它提示循环依赖,但我不知道如何注册它。

编辑 - 这是注册:

builder.RegisterAssemblyTypes(typeof(ICustomerRepository).Assembly)
   .Where(t => t.Name.EndsWith("Repository"))
   .AsImplementedInterfaces()
   .SingleInstance();

编辑 - 现在注册:

builder.RegisterAssemblyTypes(typeof(ICustomerRepository).Assembly)
   .Where(t => t.Name.EndsWith("Repository") && !t.Name.StartsWith("Cached"))
   .AsImplementedInterfaces()
   .SingleInstance();

此后,将注册每个缓存的存储库。

最佳答案

看起来你有一个装饰器,而不是循环依赖。我假设主要实现称为 CustomerRepository。注册的最简单方法是

var cb = new ContainerBuilder();

cb.RegisterType<CustomerRepository>().AsSelf();

cb.Register(c => new CachedCustomerRepository(c.Resolve<CustomerRepository>()))
    .As<ICustomerRepository>();

这是通过将主实现注册为其本身,然后将装饰器注册为 ICustomerRepository 来实现的。因此,当 Autofac 需要解析 ICustomerRepository 时,它将提供装饰器。

编辑

既然我看到了您的注册码,如果您想避免在组合根目录中进行手动工作,我可以建议您这样做。 (当然,如果你的存储库少于 10 个,我可能会使用更简单、更手动的版本)

var cb = new ContainerBuilder();

foreach (var type in this.GetType().Assembly.GetTypes()
    .Where(t => t.IsClass && !t.IsAbstract))
{
    var iRepoType = type.GetInterfaces()
            .SingleOrDefault(i => i.Name.EndsWith("Repository"));

    if (iRepoType == null)
    {
        continue;
    }

    bool isRepo = type.Name.EndsWith("Repository");
    bool isCache = type.Name.StartsWith("Cache");

    if (isRepo && !isCache)
    {
        cb.RegisterType(type)
            .Named("mainImpl", iRepoType)
            .SingleInstance();
    }
    else if (isRepo && isCache)
    {
        cb.RegisterType(type).WithParameter(
            (prop, context) => prop.ParameterType == iRepoType,
            (prop, context) => context.ResolveNamed("mainImpl", iRepoType))
            .As(iRepoType)
            .SingleInstance();
    }
}

var container = cb.Build();

var repo = container.Resolve<ICustomerRepository>();
Assert.IsInstanceOfType(repo, typeof(CachedCustomerRepository));
var cast = (CachedCustomerRepository)repo;
Assert.IsInstanceOfType(cast.wrapped, typeof(CustomerRepository));

关于autofac - 如何在Autofac中注册循环类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18848677/

相关文章:

c# - 了解 Mediatr 的 Autofac 配置

c++ - 如何解决 C++ 中友元声明的循环依赖?

c++ - 如何去除这种循环依赖

c# - Autofac 日志记录模块和 ASP.Net Web 表单中的解析参数

ninject - Ninject 是否支持 Func(自动生成工厂)?

c++ - 嵌套名称说明符中使用的不完整类型

c++ - 比可转换类型的循环依赖更好的设计

python - 动态更改 urwid.MainLoop 小部件的首选方法

c# - 使用 Autofac 解析通用接口(interface)

domain-driven-design - 用标志交换存储库