본문 바로가기
ASP.NET MVC

ASP.NET MVC 4] 종속성 주입 (Dependency Injection)

by Fastlane 2022. 1. 3.
728x90
반응형

출처 : https://docs.microsoft.com/ko-kr/aspnet/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection

 

DI (Dependency Injection) 디자인 패턴의 목표 

종속성 주입 패턴은 골프에 비유할 수 있다. 

고객이 클럽을 요청했을때, 훌륭한 캐디는 상황에 맞는 클럽을 전달해준다. 

고객은 굳이 구체적인 클럽 이름을 알려줄 필요가 없다. 

티샷을 날릴때는 WoodClub, 방향과 정확도에 집중할때는 IronClub, 그린 근처에서 온그린 할때는 WedgeClub, 그린에서 홀컵에 공을 넣을때는 PutterClub이라는 논리가 캐디 머리속에 있기 때문에, 고객은 단순히 클럽만 요구하면 된다. 

 

유지보수 관점에서 DI의 장점을 알아보자!

코드속의 tight-coupling을 줄이고, 유지보수가 쉬워지도록 한다. 

 

1. DI를 사용하지 않은 경우 

 

Class1에서 Class2를 사용하는 경우, Class1은 Class2에 의존한다고 한다. Class1에서 Class2를 사용하기 위해서 new key를 사용하여 새로운 object를 선언한다. 

작은 규모의 application이나 class가 많지 않은 경우 이렇게 사용해도 된다. 이렇게 사용하는 것을 Tight Coupled되었다고 한다. 더이상 Class2를 사용하지 않는 경우, Class2를 사용하는 모두 Class에서 Class2 -> Class3로 변경해야 한다. 

많은 Class에서 사용하는 경우, 유지보수에 어려움이 있다. 

 

 

2. DI를 사용하는 경우 

 

Class1의 constructor에 interface2를 사용하면 Service Container에 Interface2와 매핑된 Class2라는 Concrete Class를 주입한다. Class2 -> Class3으로 변경하기 위해서는 Service Container의 매핑된 Class만 변경하면 된다. 

 

Unity NuGet Package 설치 

Install-Package Unity.Mvc3

 

 

설치 후, package.config 파일을 확인해보면 아래 소스가 추가된 것을 확인할 수 있다. 

  <package id="CommonServiceLocator" version="1.0" targetFramework="net45" />
  <package id="Unity" version="2.1.505.0" targetFramework="net45" />
  <package id="Unity.Mvc3" version="1.2" targetFramework="net45" />

 

Bootstrapper.cs 파일도 프로젝트에 자동으로 추가된다. 

Global.asax.cs 에 Unity 등록

Application_Start() 함수에 Bootstrapper.Initialise(); 추가 

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            Bootstrapper.Initialise();
        }

 

인터페이스와 클래스 만들기 

BannerService.cs

interface는 별도의 cs파일을 만들어 분리하는 것이 좋다. 

다른 데서 쓸 일이 없을 때는 같은 파일에 넣어도 무방하다. 

    public interface IBannerService
    {
        int Delete_Banner(int idx);
    }

    public class BannerService : IBannerService
    {

        #region 배너리스트 삭제하기
        public int Delete_Banner(int idx)
        {
            DapperManager dm = new DapperManager(DB_StrName.DB);
            return dm.DeleteRow(idx, "T_BANNER");
        }
        #endregion
    }

 

Bootstrapper.cs 파일 BuildUnityContainer 함수에 의존성 주입 클래스 정의 

            container.RegisterType<IBannerService, BannerService>();

container에 IBannerService를 요청하면 BannerService instance를 반환한다. 

 

전체소스 

    public static class Bootstrapper
    {
        public static void Initialise()
        {
            var container = BuildUnityContainer();

            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }

        private static IUnityContainer BuildUnityContainer()
        {
            var container = new UnityContainer();

            // register all your components with the container here
            // it is NOT necessary to register your controllers

            container.RegisterType<IBannerService, BannerService>();
            // e.g. container.RegisterType<ITestService, TestService>();            

            return container;
        }
    }

요청이 끝나면, component는 IDisposable에 의해 적절히 dispose된다. 

Controller에 주입

    public class BannerController : BaseController
    {
        private IBannerService service;

        public BannerController(IBannerService service)
        {
            this.service = service;
        }
        
        // POST: Banner/Delete/5
        [HttpPost]
        public JsonResult Delete(FormCollection collection)
        {
            try
            {
                // TODO: Add delete logic here
                int bannerIdx = int.Parse(collection["bannerIdx"]);
                Banner banner = service.Get_Banner(bannerIdx);

                FileManager fileManager = new FileManager();
                fileManager.FileDelete(banner.FileName, AttachFilePath.Banner_AttachedFilePath);

                service.Delete_Banner(bannerIdx);

                return Json(new { result = "ok" });
            }
            catch(Exception ex)
            {
                return Json(new { result = ex.Message });
            }
        }
    }

 

동일한 interface를 여러 class에서 구현한 경우, 아래와 같이 사용 가능하다. 

 

Bootstrapper.cs

            container.RegisterType<IBannerService, WebBannerService>("Web");
            container.RegisterType<IBannerService, MobileBannerService>("Mobile");

Service Injection에 name을 지정한다. 

 

BannerController.cs

    using Microsoft.Practices.Unity;

    public class BannerController : BaseController
    {
        private IBannerService service;

        public BannerController([Dependency("Mobile")] IBannerService service)
        {
            this.service = service;
        }
        
    }

Microsoft.Practices.Unity.DependencyAttribute를 사용하여 원하는 injection name을 지정할 수 있다. 

 

 

728x90
반응형

댓글