Section 44.1: C# 과 ASP.NET 에서 Unity 를 통한 Dependency Injection 사용하기
우선적으로, 사용자의 코드에서 Dependency Injection 을 사용하여야 할 이유는 무엇일까? 이는 사용자의 프로그램 내 특정 구성 요소 (component) 들을 다른 클래스들로부터 분리 (decouple) 하기 위함이다. 다음과 같은 AnimalController
클래스가 있다고 가정을 해보자:
public class AnimalController() {
private SantaAndHisReindeer _SantaAndHisReindeer = new SantaAndHisReindeer();
public AnimalController() {
Console.WriteLine("");
}
}
해당 코드 자체만 보면 아무런 문제가 없다고 생각할 수도 있겠지만, 이러한 경우 AnimalController
는 _SantaAndHisReindeer
객체 자체에 의존성을 갖게 된다. 이로 인해 우리의 Controller 는 테스트하기 어려운 구조를 갖게 되며, 코드의 재사용성 역시 나빠지는 결과를 초래하게 된다.
Depedency Injection 과 인터페이스를 사용해야 하는 이유에 대해서는 이곳 에 설명이 상세히 되어 있다.
만약 Unity 가 DI (Dependency Injection) 를 처리하게 하고자 한다면, 해당 과정은 매우 간단하다. NuGet (패키지 관리자) 을 이용하여 손쉽게 기존 코드에 Unity 를 import 할 수 있다.
Visual Studio Tools -> NuGet Package Manager -> Manage Packages for Solution -> 검색창에서 Unity 입력 -> 프로젝트 선택 -> 설치
이제 주석이 잘 달려있는 두개의 파일이 생성될 것이다 : App-Data 폴더 내의 UnityConfig.cs
와 UnityMvcActivator.cs
UnityConfig
의 RegisterTypes
메소드에서는, 사용자의 생성자에서 주입될 타입들을 확인할 수 있다.
namespace Vegan.WebUi.App_Start {
public class UnityConfig {
#region Unity Container
private static Lazy < IUnityContainer > container = new Lazy < IUnityContainer > (() => {
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer() {
return container.Value;
}
#endregion
/// <summary>Registers the type mappings with the Unity container.</summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered. < /remarks>
public static void RegisterTypes(IUnityContainer container) {
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType<IProductRepository, ProductRepository>();
container.RegisterType < ISanta, SantaAndHisReindeer > ();
}
}
}
UnityMvcActivator
-> 마찬가지로 해당 클래스가 Unity 를 ASP.NET MVC 와 연동시켜 줄 것이라는 상세한 주석을 확인할 수 있다.
using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;
[assembly:
WebActivatorEx.PreApplicationStartMethod(typeof (Vegan.WebUi.App_Start.UnityWebActivator), "Start")
]
[assembly:
WebActivatorEx.ApplicationShutdownMethod(typeof (Vegan.WebUi.App_Start.UnityWebActivator),
"Shutdown")
]
namespace Vegan.WebUi.App_Start {
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
public static class UnityWebActivator {
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start() {
var container = UnityConfig.GetConfiguredContainer();
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType < FilterAttributeFilterProvider > ().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
//
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof (UnityPerRequestHttpModule));
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown() {
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
}
이제 우리는 Controller 를 SantAndHisReindeer
클래스로부터 분리할 수 있다.
public class AnimalController() {
private readonly SantaAndHisReindeer _SantaAndHisReindeer;
public AnimalController(SantaAndHisReindeer SantaAndHisReindeer) {
_SantAndHisReindeer = SantaAndHisReindeer;
}
}
이제 최종적으로 어플리케이션을 실행하기 전 수행해주어야 하는 마지막 작업이 남아있다.
Global.asax.cs
에서 다음과 같은 코드를 추가해 주어야 한다:
UnityWebActivator.Start()
이는 Unity 를 시작 및 구성하며 사용자의 타입들을 등록해 줄 것이다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Vegan.WebUi.App_Start;
namespace Vegan.WebUi {
public class MvcApplication: System.Web.HttpApplication {
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
UnityWebActivator.Start();
}
}
}
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.
[출처] https://books.goalkicker.com/CSharpBook/
'번역 > C# Notes for Professionals' 카테고리의 다른 글
45: Partial 클래스와 Partial 메소드 (0) | 2022.07.26 |
---|---|
44.2: MEF 를 이용한 Dependency injection (0) | 2022.07.26 |
43.4: 지연된, 스레드-안전한 Singleton (.NET 3.5 나 이전 버전들을 위한 대체 구현) (0) | 2022.07.25 |
43.3: 스레드-안전한 지연된 Singleton (Double Checked Locking - 이중 검사 잠금 방식) (0) | 2022.07.25 |
43.2: Lazy<T> 를 이용한 지연된 (lazy) 방식의 스레드-안전한 Singleton (0) | 2022.05.19 |