2013-09-17 2 views
2

У меня есть интерфейс и класс репозитория. У меня также есть служебный интерфейс и класс, которые зависят от интерфейса репозитория. Типичный DI. Моя цель - добавить кеширование между сервисом и репозиторием, а не коснуться службы или репозитория. Вот код:Как зарегистрировать круглый тип в Autofac?

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

Я сделал это с замком Виндзор. Я просто добавил класс, и он работал сразу, без каких-либо изменений в регистрации. Для меня это был потрясающий эффект! :) Теперь я пытаюсь сделать то же самое с Autofac, но с ошибкой. Он жалуется на круговую зависимость, и я не знаю, как ее зарегистрировать.

Edit - здесь регистрация:

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

Edit - вот регистрация в настоящее время:

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

и после этого будет регистрация для каждого кэшированного хранилища.

+1

Пожалуйста, обновите ваш пост с текущим регистрационным кодом Autofac и точное сообщение об ошибке! – nemesv

+0

Для этого Autofac имеет метод [RegisterDecorator] (http://nblumhardt.com/2011/01/decorator-support-in-autofac-2-4/). – Steven

ответ

1

Похоже, у вас есть декоратор, а не круговая зависимость. Я собираюсь предположить, что основная реализация называется 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)); 
+0

Спасибо! С помощью этой техники это сработало. Сначала я регистрирую все репозитории с одним вызовом, игнорируя кешированные версии, чтобы избежать исключения при регистрации. Autofac использует самую последнюю регистрацию. Затем мне нужно добавить эти две строки для каждого кэшированного репозитория. Это ручная работа в корне композиции, но дело здесь не в том, чтобы коснуться кода. – jmutex

+0

Если «ручная работа» беспокоит вас, я добавил редактирование, в котором показано, как вы можете избежать этого. –

+0

Спасибо, например, как зарегистрироваться. Это полезный пример того, как и почему использовать именованную регистрацию. Я задался вопросом, где это будет необходимо. Кроме того, моя голова была немного ограничена, потому что я думал регистрировать вещи на одной линии; и не использовать циклы. – jmutex

1

Существует a wiki page on the Autofac site here explaining how to register circular dependencies и какие типы отношений поддерживаются. Скорее всего, вам нужно будет переключить одну из зависимостей в вашей системе как зависимость свойств, а не на аргумент конструктора - зависимости конструктора/конструктора не поддерживаются.

Смежные вопросы