Programing

Ioc / DI-응용 프로그램 진입 점에서 모든 레이어 / 어셈블리를 참조해야하는 이유는 무엇입니까?

crosscheck 2020. 7. 25. 10:32
반응형

Ioc / DI-응용 프로그램 진입 점에서 모든 레이어 / 어셈블리를 참조해야하는 이유는 무엇입니까?


(이 질문과 관련하여 EF4 : 지연 로딩이 활성화 될 때 프록시 생성을 활성화해야하는 이유는 무엇입니까? ).

나는 DI를 처음 사용하므로 나와 함께하십시오. 컨테이너가 등록 된 모든 유형을 인스턴스화하는 책임이 있음을 이해하지만 그렇게하려면 내 솔루션의 모든 DLL에 대한 참조와 해당 참조가 필요합니다.

DI 컨테이너를 사용하지 않는 경우 MVC3 앱에서 EntityFramework 라이브러리를 참조하지 않아도되며 비즈니스 계층 만 DAL / Repo 계층을 참조합니다.

하루가 끝나면 모든 DLL이 bin 폴더에 포함되지만 내 문제는 필요한 모든 파일을 사용하여 WAP를 게시 할 수 있도록 VS의 "참조 추가"를 통해 명시 적으로 참조해야한다는 것을 알고 있습니다.


DI 컨테이너를 사용하지 않는 경우 MVC3 앱에서 EntityFramework 라이브러리를 참조하지 않아도되며 DAL / Repo 계층을 참조하는 비즈니스 계층 만 필요합니다.

그렇습니다. DI가 피하기 어려운 상황입니다. :)

밀접하게 결합 된 코드를 사용하면 각 라이브러리에 참조가 몇 개만있을 수 있지만 다시 참조가 있으므로 다음과 같이 종속성에 대한 심층 그래프가 만들어집니다.

딥 그래프

의존성 그래프가 깊기 때문에 대부분의 라이브러리는 다른 많은 종속성을 따라 드래그합니다 (예 : 다이어그램에서 라이브러리 C라이브러리 H, 라이브러리 E, 라이브러리 J, 라이브러리 M, 라이브러리 K라이브러리 N을 따라 드래그 함) . 따라서 단위 테스트와 같이 나머지와는 별도로 각 라이브러리를 재사용하기가 더 어려워집니다 .

그러나 느슨하게 연결된 응용 프로그램에서 모든 참조를 Composition Root 로 이동하면 종속성 그래프가 심각하게 평탄화됩니다 .

얕은 그래프

녹색으로 표시된 것처럼 이제 원하지 않는 종속성을 따라 드래그하지 않고도 라이브러리 C 를 재사용 할 수 있습니다 .

그러나 많은 DI 컨테이너로 말했다 모든, 당신은하지 않습니다 필요한 모든 라이브러리 하드 참조를 추가 할 수 있습니다. 대신 컨벤션 기반 어셈블리 검색 (선호) 또는 XML 구성의 형태로 후기 바인딩을 사용할 수 있습니다 .

그러나 이렇게하면 더 이상 자동으로 발생하지 않으므로 어셈블리를 응용 프로그램의 bin 폴더에 복사해야합니다. 개인적으로, 나는 그 추가 노력의 가치가 거의 없다고 생각합니다.

이 답변의 더 정교한 버전은 필자의 책 Dependency Injection, Principles, Practices, Patterns 에서 발췌 한 내용 에서 찾을 수 있습니다 .


DI 컨테이너를 사용하지 않았다면 MVC3 앱에서 EntityFramework 라이브러리를 참조 할 필요가 없습니다.

DI 컨테이너를 사용하는 경우에도 MVC3 프로젝트가 EF를 참조하도록 할 필요는 없지만 MVC3 프로젝트 내에 컴포지션 루트 (객체 그래프를 작성하는 시작 경로) 를 구현하여이를 암시 적으로 선택합니다 . 어셈블리를 사용하여 아키텍처 경계를 보호하는 데 매우 엄격한 경우 컴포지션 루트 또는 (MVC) 프레젠테이션 항목을 클래스 라이브러리로 옮길 수 있습니다.

첫 번째 옵션에서는 MVC3 프로젝트가이 별도의 '부트 래퍼'어셈블리를 참조하게하고 솔루션의 다른 모든 어셈블리를 참조하고 DI 컨테이너 라이브러리를 참조합니다. 이 문제는이 부트 스트 래퍼 프로젝트가 MVC3 프로젝트에있는 유형을 참조 할 수 없다는 것입니다 (순환 어셈블리 종속성이 발생하기 때문에). 이러한 유형은 부트 스트 래퍼 프로젝트 (System.Web.Mvc를 참조해야 할 수도 있음)로 이동하거나 컨테이너 구성의 일부를 MVC3 앱 내부에 유지해야합니다. 또한 어셈블리 의존성이 전이 적이기 때문에 MVC 프로젝트는 여전히 새 부트 스트 래퍼 어셈블리를 통해 다른 모든 어셈블리를 간접적으로 참조합니다.

컴포지션 루트를 별도의 어셈블리에 배치하는 것이 올바른 작업이지만 대부분의 DI 순수 주의자 (나 포함)는 일반적으로 여러 최종 애플리케이션 (예 : 웹 앱 + 웹 서비스 + Windows 서비스)이있는 경우 컴포지션 루트를 클래스 라이브러리로 이동합니다. )와 동일한 비즈니스 계층을 사용합니다. 단일 응용 프로그램이있을 때 컴포지션 루트를 최종 응용 프로그램 안에 유지합니다.

두 번째 옵션은 모든 MVC 관련 클래스 (뷰, 컨트롤러 등)를 시작 프로젝트에서 클래스 라이브러리로 이동하는 것입니다. 따라서이 새로운 프리젠 테이션 레이어 어셈블리는 나머지 응용 프로그램과의 연결을 끊을 수 있습니다. 웹 응용 프로그램 프로젝트 자체는 필요한 시작 논리를 가진 매우 얇은 셸이됩니다. 웹 응용 프로그램 프로젝트는 다른 모든 어셈블리를 참조하는 컴포지션 루트입니다.

Extracting the presentation logic to a class library can complicate things when working with MVC. It will be harder to wire everything up, since controllers and views, images, css files, etc. are not in the startup project. This is probably doable but will take more time to set up.

Both options have their downsides and that's why I generally advice to just keep the Composition Root in the web project. Many developers don’t want their MVC assembly to depend on the DAL assembly, but that's not really a problem. Don't forget that assemblies are a deployment artifact; you split code into multiple assemblies to allow code to be deployed separately. An architectural layer on the other hand is a logical artifact. It's very well possible (and common) to have multiple layers in the same assembly.

In this case we'll end up having the Composition Root (layer) and the Presentation Layer in the same web application project (thus in the same assembly). And even though that assembly references the assembly containing the DAL, the Presentation Layer still does not reference the Data Access Layer. This is a big distinction.

Of course, when we do this, we lose the ability for the compiler to check this architectural rule at compile time, but this shouldn't be a problem. Most architectural rules actually can't be checked by the compiler and there's always something like common sense. And if there's no common sense in your team, you can always use code reviews (which every team should IMO always do btw). You can also use a tool such as NDepend (which is commercial), which helps you verifying your architectural rules. When you integrate NDepend with your build process, it can warn you when somebody checked code in that violates such architectural rule.

You can read a more elaborate discussion on how the Composition Root works in chapter 4 of my book Dependency Injection, Principles, Practices, Patterns.


If I wasn't using an DI container, I wouldn't have to reference EntityFramework library in my MVC3 app, only my business layer which would reference my DAL/Repo layer.

You can create a seperate project called "DependencyResolver". In this project you have to reference all your libraries.

Now the UI Layer doesn't need NHibernate/EF or any other not UI relevant library except of Castle Windsor to be referenced.

If you want to hide Castle Windsor and DependencyResolver from your UI layer you could write an HttpModule which calls the IoC registry stuff.

I have only an example for StructureMap:

public class DependencyRegistrarModule : IHttpModule
{
    private static bool _dependenciesRegistered;
    private static readonly object Lock = new object();

    public void Init(HttpApplication context)
    {
        context.BeginRequest += (sender, args) => EnsureDependenciesRegistered();
    }

    public void Dispose() { }

    private static void EnsureDependenciesRegistered()
    {
        if (!_dependenciesRegistered)
        {
            lock (Lock)
            {
                if (!_dependenciesRegistered)
                {
                    ObjectFactory.ResetDefaults();

                    // Register all you dependencies here
                    ObjectFactory.Initialize(x => x.AddRegistry(new DependencyRegistry()));

                    new InitiailizeDefaultFactories().Configure();
                    _dependenciesRegistered = true;
                }
            }
        }
    }
}

public class InitiailizeDefaultFactories
{
    public void Configure()
    {
        StructureMapControllerFactory.GetController = type => ObjectFactory.GetInstance(type);
          ...
    }
 }

The DefaultControllerFactory doesn't use the IoC container directly, but it delegates to IoC container methods.

public class StructureMapControllerFactory : DefaultControllerFactory
{
    public static Func<Type, object> GetController = type =>
    {
        throw new  InvalidOperationException("The dependency callback for the StructureMapControllerFactory is not configured!");
    };

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            return base.GetControllerInstance(requestContext, controllerType);
        }
        return GetController(controllerType) as Controller;
    }
}

The GetController delegate is set in a StructureMap Registry (in Windsor it should be an Installer).


  • 객체가 다른 객체를 인스턴스화하는 경우 종속성이 있습니다.
  • 의존성이 없습니다 : 객체가 추상화를 기대한다면 (contructor injection, method injection ...)
  • 어셈블리 참조 (dll 참조, webservices ..)는 종속성 개념과 무관합니다. 추상화를 해결하고 코드를 컴파일 할 수 있으려면 계층에서이를 참조해야합니다.

참고 URL : https://stackoverflow.com/questions/9501604/ioc-di-why-do-i-have-to-reference-all-layers-assemblies-in-applications-entry

반응형