2016-11-25 3 views
0

나는 이미 성장한 Ninject DI 기반 응용 프로그램을 사용하여 작업해야만 재능이 있었고 현재 작업중인 응용 프로그램의 개발에 상당히 추가되었습니다. .Ninject를 사용한 종속성 삽입 다른 인스턴스의 동일한 객체 공유

이제 문제를 해결하고 싶습니다. 상속을 사용하여 해결하려고했지만 더 깨끗한 솔루션을 원합니다.

다른 서비스 및 저장소에 주입하려면 두 개의 연결이 필요합니다. 그런 다음 저장소가 정확하게 UnitOfWork의 올바른 서비스에 올바르게 연결되어야합니다.

나는 상속 및 전문화 없이는 불가능한 것을 묻고 있을지 모르지만 그것이 내가 묻는 이유입니다.

기본 RepositoryUnitOfWork 클래스의 하위 클래스를 생성하여이 문제를 해결할 수 있었지만 기본 클래스를 구현하는 것 외에는 아무런 변화가 없었습니다. 난 그냥 하위 클래스의 개념을 완전히 수퍼 클래스의 기능을 기본적으로 빈 중괄호와 함께 생성자에서 떨어져 의존하고 싶지 않아,이 사실 OOP 그냥이 문제를 해결하려면 보이지 않는다. 그래서 DI에서 가능한 한 일류 솔루션을 활용하여 더 나은 솔루션을 모색했습니다.

당신이 목적이 무엇인지 볼 수 아래의 코드를 보면 : 당신은 내가 완전히 변화를 복귀하기 때문에 대해 말한 솔루션을 무시할 수있는 경우

그래서 이것은 내가 남아있는 무슨이다. 무엇 내가 알고 싶은

... 

public class UnitOfWork : IUnitOfWork 
{ 
    private static readonly log4net.ILog log = log4net.LogManager.GetLogger("UnitOfWork"); 
    public DbContext DataContext { get; set; } 

    public UnitOfWork(string connectionString) 
    { 
     DataContext = new DbContext(connectionString); 
    } 

    public void Commit() 
    { 
     ... 
    } 
} 

... 

public class Repository<T> : IRepository<T> where T : class 
{ 
    public IUnitOfWork unitOfWork { get; set; } 
    private readonly IDbSet<T> dbSet; 

    //private static readonly log4net.ILog log = log4net.LogManager.GetLogger("Repository"); 

    public Repository(IUnitOfWork unitOfWork) 
    { 
     this.unitOfWork = unitOfWork; 
     dbSet = this.unitOfWork.DataContext.Set<T>(); 
    } 
    ... 
} 
... 

public class IPOPDataModules : NinjectModule 
{ 
    public override void Load() 
    { 
    Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString); 
    Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope(); 
    } 
} 

... 

public class DataModules : NinjectModule 
{ 
    public override void Load() 
    { 
    Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BAPSEntities"].ConnectionString); 
    Bind<IRepository<Data.Quote>>().To<Repository<Data.Quote>>().InRequestScope(); 
    } 
} 

... 

public class QuoteService : IQuoteService 
{ 
    private IUnitOfWork unitOfWork; 
    private IRepository<Data.Quote> quoteRepository; 
    public QuoteService(IUnitOfWork unitOfWork, IRepository<Data.Quote> quoteRepository) 
    { 
     ... 
    } 
} 

... 

public class IPOPService : IIPOPService 
{ 
    private IUnitOfWork unitOfWork; 
    private IRepository<Data.tOrder> tOrderRepository; 

    public IPOPService(IUnitOfWork unitOfWork, IRepository<Data.tOrder>) 
    { 
     ... 
    } 
} 

, 그것은 두 개의 서로 다른 연결하여 동일한 UnitOfWorkRepository 객체를 공유하고 그들을 IPOP_BE_TEST 연결에 IPOPService (각 서비스에 서로 다른 인스턴스를 주입하는 것이 가능하다 IPOP_BAP 연결을위한 QuoteService)

다시 위의 코드는 내가 원하는 것을 얻지 못한다. 그러나 이것은 내가 작동하도록하기 위해 놀고 싶은 아키텍처의 일종이다.

답변

0

귀하의 질문에 완전히 만족스럽지 않습니다. 그러나 다음 두 가지 범위에 대한 설명서를 확인하십시오. 시나리오에 따라 다를 수 있습니다.

  • InCallScope 결과로 해상도 트리 당 하나의 인스턴스 만 생성됩니다. 필자는 일반적으로이 범위를 업무 단위의 데스크톱 응용 프로그램에서 사용합니다. 설명서 here을 참조하십시오. 이 경우에는 Ninject.Extensions.NamedScope 확장 프로그램이 필요합니다.
  • InRequestScope 웹 응용 프로그램에서 HTTP 요청 당 하나의 인스턴스 만 생성됩니다. 나는 보통 작업 단위에이 범위를 사용합니다. 설명서 here을 참조하십시오. 이 경우 Ninject.Web.Common 패키지가 필요합니다.
+0

@Zoltan 입력에 감사드립니다. MVC 사이트에서 작업 중이며 일부 혼란을 야기 할 수있는 질문에 약간의 변경을가했습니다. 위의 대답에 대해서는 어떻게 든 정확한 'UnitOfWork'와'Repository'(올바른 db 연결을 사용하여)를 위의 두 가지 서로 다른 서비스에 매핑 할 수 있기를 원합니다. 나는 가능하다면 그 일을 할 수있는 몇 가지 Ninject 로직을 놓치고 있다고 생각한다. – Saleh

0

당신이 찾고있는 것은 Ninject 바인딩 범위입니다. 바인딩을 선언 할 때마다 Ninject는 활성화 프로세스가 해당 서비스의 새 인스턴스를 만들어야하는지 또는 이전에 생성 된 인스턴스를 반환해야 하는지를 결정하기 위해 사용하는 바인딩에 대한 대리인을 제공합니다.당신이 Ninject에있는 싱글 톤을 구현하려는 경우

그래서, 당신은 단순히 선언 • 그래도 다음과 같습니다 바인딩 :

Bind<IRepository<Data.Quote>>().To<Repository<Data.Quote>>().InSingletonScope(); 

InSingletonScope()InRequestScope()는 단순히 설탕이다 (또는 InRequestScope 확장 메서드의 경우) 그래도 InScope(Func<Ninject.Activation.IContext, object> scope) 방법의 경우 IBindingInSyntax<T>에 있습니다. 주어진 상황에서 Ninject가 동일한 서비스 인스턴스를 반환하도록하려면 언제든지 사용자 정의 범위를 구현해야합니다.

질문을 올바르게 이해하면 요청이 응용 프로그램에 도달 할 때 Repository<T>IUnitOfWork의 동일한 인스턴스가 응용 프로그램의 모든 서비스에 주입되도록하고 싶습니다. 이 경우 당신은 단순히 같은 바인딩을 작성해야 :

Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString); 
Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope(); 

그러나, 문제는 두 개의 별도의 바인딩, 두 개의 별도의 모듈을 가지고 것으로 보인다. 어떤 연결 문자열을 시스템의 어느 부분에 제공해야 하는지를 결정하기 위해 상황에 맞는 바인딩을 가진 단일 모듈을 사용해야 할 것을 제안합니다. 그래서 하나 개의 모듈은 다음과 같습니다 IQuoteService를 해석 할 때

Bind<IUnitOfWork>() 
    .To<UnitOfWork>() 
    .WhenInjectedInto<IIPOPService>() 
    .InRequestScope() 
    .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString); 
Bind<IUnitOfWork>() 
    .To<UnitOfWork>() 
    .WhenInjectedInto<IQuoteService>() 
    .InRequestScope() 
    .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BAPSEntities"].ConnectionString); 

Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope(); 

당신이 Ninject에이 IIPOPService를 해결하는 경우가 "IPOP_BE_TESTEntities" 연결 문자열로 초기화 UnitOfWork의 인스턴스를 생성시킬 것이라는 점을 확실 할 수있다이 방법을, 그리고 그것을 사용합니다 "IPOP_BAPSEntities" 연결 문자열이지만 그렇지 않은 경우 해당 요청 범위에서 단일 인스턴스 만 Ninject에 의해 생성됩니다.

희망이 도움이됩니다.

+0

당신의 제안에 감사드립니다 @ s3raph86, 불행히도 거기에 IIPOPService 및 IQuoteService과 비슷한 40 이상한 서비스가 있으며 가능한 경우 최소한의 코드 변경 사항을 모두 수용 할 수있는 경우 더 우아한 솔루션이 있는지 궁금 해서요. – Saleh

+0

그게 딜 브레이커가되어서는 안됩니다 @Saleh - Ninject는 문맥 적 바인딩을위한 많은 옵션을 제공합니다. 하나의 연결 문자열 또는 다른 연결 문자열을 적용하기로 결정할 때 사용해야 할 규칙에 대해 무엇을 말해 줄 수 있습니까? 속성을 정의하여 서비스를 꾸미고 바인딩에서 사용할 수 있습니까? – s3raph86

+0

현재 응용 프로그램은 3 conns 이상을 지원합니다 (위의 질문은 2의 예를 보여줍니다). 최소한의 코드 변경만으로도 가능한지 확실하지 않습니다. 여러 저장소와 서비스에 대해 'IPOP_BAPS'라고 말하는 conn을 가진 UnitOfWork를 지정하고 동시에 다른 연결을 가진 다른 UnitOfWork를 다른 집합으로 지정하려고합니다. 리포지토리 및 서비스. 또한 저장소가 서비스에 삽입되기 때문에 서비스와 저장소에있는 UnitOfwork는 동일해야합니다. 서비스는 재사용 할 필요가 없지만 재사용하고자하는 저장소입니다. – Saleh

관련 문제