2014-02-05 3 views
2

У меня есть несколько многоязычных веб-сайтов, работающих под одним веб-приложением. Каждый «локаль» имеет собственное ядро ​​Solr (с одинаковыми полями во всех локалях). Я использую SolrNet для выполнения моих поисковых запросов.Устранение соединительной муфты IoC на заводе

Для переключения ядер на основе каждого запроса, я регистрации именованный экземпляр из ISolrOperations<SearchResult> в моем Autofac контейнере для каждого региона (для тех, кто не знаком с SolrNet, это эффективно моя точка входа в библиотеку запросов).

Я тогда интерфейс ISearchService, с бетонным SolrSearchService реализации, чей конструктор подписи выглядит следующим образом:

public SolrSearchService(ISolrOperations<SearchResult> solr) 

Для динамического переключения ядер на каждом запросе, мой контроллер принимает (впрыскивается) ISearchServiceFactory вместо просто ISearchService. Моя SolrSearchServiceFactory выглядит следующим образом:

public class SolrSearchServiceFactory : ISearchServiceFactory 
{ 
    private readonly IComponentContext _ctx; 

    public SolrSearchServiceFactory(IComponentContext ctx) 
    { 
     _ctx = ctx; 
    } 

    public ISearchService Create(string id) 
    { 
     var result = _ctx.ResolveNamed<ISolrOperations<SearchResult>>(id); 
     return new SolrSearchService(result); 
    } 
} 

id просто идентификатор локали. Это лучшее, что мне удалось сделать, чтобы отделить Autofac от моих сервисов/контроллеров, но сохранить возможность переключения ядер на запрос (на основе логики, выполняемой в контроллере).

Я все еще не очень доволен этим, однако, поскольку сама фабрика по-прежнему связана с Autofac. Есть ли способ обойти это (с точки зрения SolrNet или Autofac)?

Я рассмотрел использование делегатов фабрики Autofac, но, похоже, не существует способа применить их в этом экземпляре.

+1

Нужно ли вам иметь именованные экземпляры? – DavidN

+0

@DavidN Не обязательно именованные экземпляры, но I * do * нужен способ переключения экземпляров того же типа (с тем же аргументом типа). Я был против раввинов, пытаясь переключить конечную точку одного соединения SolrNet, и я не вернусь!По сути, фактический URL-адрес конечной точки вводится в зависимость от зависимости от ISolrOperations, а сама библиотека очень сильно загружается, поэтому не сложно построить каждый запрос за пределами предоставленных модулей DI. –

ответ

1

Для этого вы можете использовать сервисы с ключами/именами и IIndex, есть хорошая запись на странице автофайла here.

Вот краткий пример того, что бы выглядеть следующим образом:

public class Factory 
    { 
     private readonly IIndex<string, ISearchService> _index; 

     public Factory(IIndex<string, ISearchService> index) 
     { 
      _index = index; 
     } 

     public ISearchService Resolve(string id) 
     { 
      return _index[id]; 
     } 
    } 

     // Registrations 
     var builder = new ContainerBuilder(); 
     builder.Register<ASearchService>(c => new ASearchService()).Keyed<ISearchService>("A"); 
     builder.Register<BSearchService>(c => new BSearchService()).Keyed<ISearchService>("B"); 
     builder.Register<Factory>(c => new Factory(c.Resolve<IIndex<string, ISearchService>>())); 
     // as per autofac's page linked above, autofac automatically implements IIndex types 

     // Usage 

     var aSearchService = fact.Resolve("A"); 

EDIT: Я думал, что мы могли бы сделать лучше, чем это, так вот несколько методов расширения, чтобы избежать создания явного завода класс:

public delegate TReturn AutoFactoryDelegate<TParam, TReturn>(TParam param); 

    public class AutoFactory<TParam, TReturn> 
    { 
     private readonly IIndex<TParam, TReturn> _index; 

     public AutoFactory(IIndex<TParam, TReturn> index) 
     { 
      _index = index; 
     } 

     public TReturn Resolve(TParam param) 
     { 
      return _index[param]; 
     } 
    } 

    public delegate TReturn AutoFactoryDelegate<TParam, TReturn>(TParam param); 

    public static class AutofacExtensions 
    { 
     public static void RegisterAutoFactoryDelegate<TParam, TReturn>(this ContainerBuilder builder) 
     { 
      builder.Register(c => new AutoFactory<TParam, TReturn>(c.Resolve<IIndex<TParam, TReturn>>())); 

      builder.Register<AutoFactoryDelegate<TParam, TReturn>>(c => 
       { 
       var fact = c.Resolve<AutoFactory<TParam, TReturn>>(); 
       return fact.Resolve; 
       }); 
     } 
    } 

// Registration 
var builder = new ContainerBuilder(); 
builder.Register<ASearchService>(c => new ASearchService()).Keyed<ISearchService>("A"); 
builder.Register<BSearchService>(c => new BSearchService()).Keyed<ISearchService>("B"); 
builder.RegisterAutoFactoryDelegate<string, ISearchService>(); 

// Usage 
// fact is an AutoFactoryDelegate<string, ISearchService> 
var aSearchService = fact("A"); 

EDIT 2: После того, как раз, глядя на это, нам не нужны классы Factory, так как IIndex действует завод уже. Это приводит к довольно упрощению со стороны реализации:

public static void RegisterAutoFactoryDelegate<TParam, TReturn>(this ContainerBuilder builder) 
{ 
    builder.Register(c => 
         { 
          var iindex = c.Resolve<IIndex<TParam, TReturn>>(); 
          return (Func<TParam, TReturn>) (id => iindex[id]); 
         }); 
} 

// Registration 
var builder = new ContainerBuilder(); 
builder.Register<ASearchService>(c => new ASearchService()).Keyed<ISearchService>("A"); 
builder.Register<BSearchService>(c => new BSearchService()).Keyed<ISearchService>("B"); 
builder.RegisterAutoFactoryDelegate<string, ISearchService>(); 

// Usage 
// fact is an Func<string, ISearchService> 
var aSearchService = fact("A"); 
+0

Это по линиям, которые я думал с автозаводами, и вполне может быть недостающим звеном - я посмотрю завтра и вернусь к вам. Благодаря! –

+0

Не совсем то, что я делал, но указал мне в правильном направлении. Я зарегистрировал 'Func ', который просто вызывает 'c.ResolveNamed > (id)' и создает экземпляр нового экземпляра 'SolrSearchService'. Внесите это в мою существующую фабрику, поэтому мой контроллер не принимает Func (который, я думаю, немного уродлив). –

+0

Если я правильно понимаю ваше решение, у вас есть Func , который закрывается на c, который в autofac не имеет значения. Вы как-то обошли это? – DavidN

1

я не использовал Autofac, но, основываясь на том, как Виндзор делает это и то, что я только что вы должны быть в состоянии сделать что-то вроде этого

builder.Register(c => 
    new SolrSearchServiceFactory(HttpContext.Current.GetIdFromUrlOrSomething) 
    ) 
    .As<ISearchServiceFactory>() 
    .InstancePerHttpRequest(); 

Если вы можете получить идентификатор из контекста http, тогда autofac должен подключить фабрику для каждого запроса.

/Michael

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

  • Нет связанных вопросов^_^