2014-07-17 3 views
2

저는 제어 할 수없는 응용 프로그램과 함께 배포 될 클래스 라이브러리 (C#)를 작성하고 있습니다. 내 라이브러리도 보안에 민감하기 때문에 호출하는 앱이 클래스 라이브러리의 종속성을 구성하는 것을 원하지 않습니다. 독립적이어야하고 자체 의존성을 초기화해야합니다.클래스 라이브러리 내에서 IoC 컨테이너를 초기화하는 좋은 전략은 무엇입니까?

동시에 단위 테스트가 가능하고 느슨하게 결합되기를 원하며 IoC 컨테이너를 사용하여 종속성을 관리하려고합니다. 지금은 내부 생성자와 [InternalsVisibleTo()]을 사용하고 있으므로 단위 테스트에서 수동 주입을 할 수 있습니다. 나는 IinC 컨테이너로 Ninject를 사용하는 것을 선호하지만 이는 그 질문과 관련이 없다.

내가 클래스 라이브러리가 정말 정의 진입 점을 가지고 있지 않기 때문에, 생산에서 내 IoC 컨테이너를 초기화하기위한 좋은 전략을 마련하기 위해 사투를 벌인거야, 그것은 인스턴스화 할 수있는 클래스의 번호를 가지고 앱이 먼저 사용할 앱을 알 수있는 방법이 없습니다.

AssemblyLoad 이벤트의 어떤 종류의, 그리고 실제로 AppDomain이 같은 이벤트를 갖고있는 것 같아요,하지만 난 심지어로 연결할 수 있습니다 전에 내 어셈블리가 이미 응용 프로그램 도메인에로드되어 있어야합니다, 그래서 항상 것 수 있다면 궁금

내 자신의 의회가 올려 놓은 사건을 놓치지 마라. 정적 이니셜 라이저 또는 생성자 사용에 대해서도 생각했지만 IoC 컨테이너 설정이 가능한 모든 클래스를 오염시키지 않는 이유는 컨테이너에 밀접하게 결합되어 있기 때문입니다. IoC 컨테이너에 연결하기 위해서만 코드를 디커플링하고 싶지는 않습니다.

이 주제에 관해 논의한 몇 가지 다른 질문을 찾았지만 그 중 아무도 내 상황을 다루지 않았습니다. 하나는 정적 이니셜 라이저를 사용하는 것이 좋습니다. 다른 하나는 응용 프로그램이 항상 구성 루트가되어야한다고 제안하는 것입니다.

다른 방법이 있습니까?

+0

고객이 구현물을 얻기 위해 Ninject를 사용합니까? 그렇지 않다면, 어떻게 Ninject를 사용하여 수업에 어떤 것을 주입 할 계획입니까? –

+0

내 소비자가 Ninject를 사용하거나 사용하지 않을 수도 있습니다. 잘 모르겠습니다. 내 클래스 라이브러리는 NuGet 패키지로 소비 될 것이므로 해당 수준의 Ninject에 의존 할 것입니다. –

답변

1

여기에 두 가지 시나리오가 있습니다

A)는 귀하의 소비자는 Ninject에 컨테이너를 사용하지 않는 : 당신이 그들을 대체 구성을 제공 할 수 싶지 않아 (또는 내부 클래스를 주입하는 경우

), 이러한 종속성을 스스로 해결할 생성자를 만들어야합니다. 이것이 귀하의 입국 지점이 될 것입니다.

B) 당신 소비자 있습니다 당신의 Ninject에 컨테이너 사용 : 당신은 당신의 소비자에게 당신의 Ninject에 커널 인스턴스를 노출해야합니다

합니다. Ninject를 사용하고 있다는 사실을 숨기고 싶거나 단순히 커널 자체를 드러내기만하면 ServiceLocator에 래핑 될 수 있습니다. 두 경우 모두 정적 클래스에서 속성을 입력 지점으로 사용할 수 있습니다.

내부적 인 관점에서 옵션 B를 사용하는 것을 선호하지만 제 3 자 라이브러리를 자주 사용하는 소비자는 IoC 컨테이너를 공개 한 적이 없으며 내가 원하는 것은 아닙니다. 난 단지 클래스를 인스턴스화하고 내부 구현이나 의존성에 대해 걱정할 필요가 없다. 당신은 물론 다를 수 있습니다.

+0

+1 감사합니다. 나는 내 상황에 가장 잘 맞다고 생각한다. 나는 그것을 잠시 동안 궁리 할 것이다. –

4

요구 사항간에 모순이 있습니다.

첫째, 보안 우려로 인해 합성 루트가 필요하지 않습니다. 둘째로, 의존성을 컨테이너가 해결하기를 원한다.그러나 라이브러리가 콘테이너를 제어하지 않기 때문에, 내부에서 무엇이든 해독하려고하는 것을 포함하여 거의 모든 것이 코드에 삽입 될 수 있습니다.

한 가지 방법은 종속성을 명시 적으로 지정하여 라이브러리 클라이언트가 종속성을 제공하도록하는 것입니다. 라이브러리는 여전히 라이브러리가 오염 된 것을 의미하지 않는다 초기화의 명시 적 외부 지점 인 구성 루트를 사용하는 반면에

namespace Library 
{ 
    public class Foo1 
    { 
     // a classical IoC dependendency 
     public Foo1(IBar bar) 
     { 
     } 
    } 
} 

. CR은 내부 개체 생성을 담당하는 Local Factory (일명 Dependency Resolver)와 잘 작동하며 CR 내에서 설정됩니다.
namespace Library 
{ 
    public interface IFoo { } 

    // local Foo factory, with a customizable provider 
    public class FooFactory 
    { 
     private static Func<IFoo> _provider; 
     public static void SetProvider(Func<IFoo> provider) 
     { 
      _provider = provider; 
     } 

     public IFoo CreateFoo() 
     { 
      return _provider(); 
     } 
    } 

    // Bar needs Foo 
    public class Bar 
    { 
     public void Something() 
     { 
      // you can use the factory here safely 
      // but the actual provider is configured elsewhere 
      FooFactory factory = new FooFactory(); 

      IFoo foo = factory.CreateFoo(); 
     } 
    } 
} 

다음 어딘가에 구성 루트에서

// kernel is set up to map IFoo to an implementation of your choice 
public void ComposeRoot(IKernel kernel) 
{ 
    FooFactory.SetProvider(() => kernel.Get<IFoo>()); 
} 

당신이 볼 대신 가능한 여러 클래스에서 여러 주입 지점을 제공 할 수 있듯이 (가까운 응용 프로그램의 엔트리 포인트)

는 현지 공장 하나입니다 자체 주입 식으로 전체 라이브러리를 깨끗하게 구성 할 수 있습니다.

IoC 컨테이너를 포함하지 않고 구체적인 구현을 작성하여 컨테이너가 없어도 쉽게 테스트 할 수있는 공급자를 가질 수도 있습니다. 다른 IoC로 전환하는 것은 간단하며 다른 공급자를 제공하기 만하면됩니다.

라이브러리가 커지고 수업이 응집 될 때 (서로 자주 사용하는 경우) 로컬 팩토리를 갖는 것이 더 편리합니다. 오히려, 모든 클래스가 하나의 공장에 달려 있습니다 (클래스 A 요구 I하고 B 요구 A가 자동으로 B 요구 I이 경우, 로컬 공장없이) 종속 수업 사이 다시 throw 할 필요가 없습니다.

+0

+1 Wiktor에 대해 감사드립니다. 필자는 컴퍼 지션 루트로 작동하는 애플리케이션에 의존 할 수 없기 때문에 지역 팩토리가 작동 할 수 있다고 생각합니다. 아마도 정적 초기화 프로그램에서 구성되었을 것입니다. –

+0

문제는 라이브러리가 Ninject에 직접 종속되는 것을 원하지 않는다는 것입니다. 이니셜 라이저는 외부에 있어야합니다. 구성 루트는 일반적인 장소이며 예, 당신이 그것에 의존 할 수 있다고 믿습니다. 팩토리 메서드가 호출되었지만 이니셜 라이저가 이전에 호출되지 않았 으면 예외를 throw합니다. 예외는 "초기화 메소드는 factory 메소드를 호출하기 전에 호출되어야한다"고 말합니다. 누군가가 쉽게 고칠 수 있도록 잘못된 것이 무엇인지 명확하게 알려줍니다. –

+0

그것에 대해 더 생각하면할수록이 접근법에 더 몰입하게됩니다. 나는 Ninject를 사용하는 것을 잊어 버리고 일종의 static initializer를 가진 팩토리 클래스를 가지고 있다고 생각한다. 최소한이 방법으로는 팩토리 클래스에만 연결되고 외부에는 연결되지 않습니다. 나는 조금 실험하고 다시보고 할 것이다. –