2014-02-05 1 views
2

단일 웹 응용 프로그램에서 여러 언어로 된 "웹 사이트"를 운영합니다. 각 "로켈"에는 자체로 구성된 Solr 코어 (모든 로케일에서 동일한 필드가 있음)가 있습니다. 내 검색 쿼리를 수행하기 위해 SolrNet을 사용하고 있습니다. 당 요청으로 코어를 전환하기 위해공장에서 IoC 컨테이너 커플 링 제거

, 나는 SolrNet에 익숙하지 않은 사람들을위한 명명 된 인스턴스 각 로케일 내 Autofac 컨테이너에 ISolrOperations<SearchResult>을 (등록하고,이 효과적으로에 대한 라이브러리로 내 진입 점입니다 쿼리 목적).

난 후 그 생성자 서명이 보이는 콘크리트 SolrSearchService 구현로하는 ISearchService 인터페이스를 가지고

동적 각 요청에 코어를 전환하기 위해
public SolrSearchService(ISolrOperations<SearchResult> solr) 

, 내 제어기는 소요 (주입) 단순히 ISearchService 대신 ISearchServiceFactory이 표시됩니다. 내 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 반드시 명명 된 인스턴스 일 필요는 없지만 동일한 유형의 인스턴스 (동일한 유형의 인수로)를 전환하는 방법이 필요합니다. 나는 단일 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"); 

편집 : 여기

는 같이했던 것과의 빠른 예제 나는 우리가 명시 적으로 공장의 생성을 미연에 방지하기 위해, 그래서 여기에 이것보다 더 잘 할 확장 방법의 커플 수 있다고 생각 클래스 :

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"); 

편집 2 : 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

내가 끝내지는 않았지만 올바른 방향으로 나를 가리켰다. 나는'c.ResolveNamed > (id)'를 호출하고'SolrSearchService'의 새로운 인스턴스를 인스턴스화하는'Func '를 등록했습니다. 내 컨트롤러가 Func 를 사용하지 않도록하기 위해 이것을 기존 공장에 주입했습니다 (추측하면 추한 것 같습니다). –

+0

당신의 솔루션을 올바르게 이해한다면, autofac에서 no-no 인 c로 닫히는 Func 가 있습니다. 어떻게 든 그 주위를 돌아 다녔어? – DavidN

1

내가 Autofac 사용하지 않은,하지만 윈저을 수행하고 내가 그냥 발견하는 것은 당신이

builder.Register(c => 
    new SolrSearchServiceFactory(HttpContext.Current.GetIdFromUrlOrSomething) 
    ) 
    .As<ISearchServiceFactory>() 
    .InstancePerHttpRequest(); 
같은 것을 할 수 있어야하는 방법에 따라

http 컨텍스트에서 ID를 얻을 수 있으면 autofac은 각 요청에 대해 공장을 연결해야합니다.

/마이클