비 컨트롤러 클래스에서 Unity MVC 4를 사용하여 DI (Dependency Injection)를 추가하는 방법

Dec 18 2020

따라서 종속성 주입을 달성하기 위해 Unity MVC-4를 사용하고 있으며 Controller클래스 와 잘 작동 하지만 컨트롤러가 아닌 클래스에 주입을 시도하자마자 NullReferenceException주입 된 객체가 프레임 워크에 의해 초기화되지 않음을 알 수 있습니다. . 내가 사용하는 해당 클래스를 제공합니다.

Controller 수업 (DI 작품) :

public class HomeController : Controller
{
    IMyService _myService;

    #region CTOR
    public HomeController(IMyService myService)
    {
        _myService = myService;
    }
    #endregion
    
    public string GetMyString()
    {
        string mystring=string.Empty;
        
        try
        {
            mystring = _myService.GetMyStringFromDLL();
        }
        catch (Exception ex)
        {
            StringBuilder str = new StringBuilder();
            str.AppendLine("Exception in method GetMyString, Error msg: " + ex.Message);
            WriteLog(sb);
        }
        return mystring;
    }
}

비 컨트롤러 메서드에서 동일한 작업을 수행하면 (DI는 여기서 작동하지 않음) NullReferenceException다음을 얻습니다 .

public inteface IMyLogic
{
    string GetMyString();
}

public class MyLogic: IMyLogic
{
    IMyService _myService;

    #region CTOR
    public MyLogic(IMyService myService)
    {
        _myService = myService;
    }
    #endregion
    
    public string GetMyString()
    {
        string mystring=string.Empty;
        
        try
        {
            mystring = _myService.GetMyStringFromDLL();  //Getting NullReferenceException here
        }
        catch (Exception ex)
        {
            StringBuilder str = new StringBuilder();
            str.AppendLine("Exception in method GetMyString, Error msg: " + ex.Message);
            WriteLog(sb);
        }
        return mystring;
    }
}

BootStrapper.cs수업은 다음과 같습니다.

public static class Bootstrapper
{

    public static IUnityContainer Initialise()
    {
      var container = BuildUnityContainer();
        container.RegisterType<IMyService , MyService>();
        container.RegisterType<IMyLogic, MyLogic>(new HierarchicalLifetimeManager());
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));

      return container;
    }

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

    public static void RegisterTypes(IUnityContainer container)
    {

    }

}

위의 행 container.RegisterType<IMyService , MyService>();을 보면 인터페이스와 구체적인 구현이 별도의 모듈에있는 것입니다.

그리고 내 Global.asax.cs:

protected void Application_Start()
{
    Bootstrapper.Initialise();
    AreaRegistration.RegisterAllAreas();
    GlobalFilters.Filters.Add(new OfflineActionFilter());
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

어떻게 삽입 할 수 IMyService에서 MyLogic클래스?

답변

4 Jackdaw Dec 21 2020 at 20:20

[InjectionConstructor] 속성을 사용 하여 Unity에 MyLogic클래스가 생성자에 삽입 될 객체에 종속되어 있음을 알립니다 .

[InjectionConstructor]
public MyLogic(IMyService myService)
{
   _myService = myService;
}

실제로 [InjectionConstructor]주입 된 클래스에 둘 이상의 생성자가 포함 된 경우 사용 하는 것이 좋습니다. 따라서이 특성은 명확성을 해결하는 데 사용됩니다. Unity질문 코드에 코드의 일부가 포함되어 있지 않기 때문에 필요한 유형을 해결할 수없는 이유는 내 가설이었습니다 . 그러나 아래의 테스트 코드에서는 [InjectionConstructor]생성자가 하나만 선언 되었기 때문에 속성이 필요하지 않습니다.

여기에 테스트 코드가 있습니다.

IMyService인터페이스 정의 :

public interface IMyService
{
    string GetMyStringFromDLL();
}

ILogic인터페이스 정의 :

public interface IMyLogic
{
    string GetMyString();
}

MyLogic구현 :

public class MyLogic : IMyLogic
{
    IMyService _myService;
       
    public MyLogic(IMyService myService)
    {
        _myService = myService;
    }
        
    public string GetMyString()
    {
        var mystring = string.Empty;
        try
        {
            mystring = "MyLogic.GetMyString() -> " + _myService.GetMyStringFromDLL();
        }
        catch (Exception ex)
        {                
            System.Diagnostics.Debug.WriteLine("Exception in method MyLogic.GetMyString(): " + ex.Message); 
        }
        return mystring;
    }
}

MyService구현 :

public class MyService : IMyService
{
    public string GetMyStringFromDLL()
    {
        return "MyService.GetMyStringFromDLL() is called.";
    }
}

Bootstrapper초기화 :

public static class Bootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = new UnityContainer();
        container.RegisterType<IMyService, MyService>();            
        container.RegisterType<IMyLogic, MyLogic>(new HierarchicalLifetimeManager()); 
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        return container;
    }
}

Home컨트롤러 구현 :

public class HomeController : Controller
{
    private readonly IMyService _myService;
    private readonly IMyLogic _myLogic;

    #region CTOR
    public HomeController(IMyService myService, IMyLogic myLogic)
    {
        _myService = myService;
        _myLogic = myLogic;
    }
    #endregion

    public ActionResult Index()
    {
        // Obtaining string directly from the IMyService
        var sService = _myService.GetMyStringFromDLL();

        // Obtaining string through the IMyLogic
        var sLogic = _myLogic.GetMyString();

        return View(new List<string>() { sService, sLogic} );
    }
}

마지막으로 Home컨트롤러 의 기본 동작 방법이 실행되면 다음 두 줄이 표시됩니다.

MyService.GetMyStringFromDLL() is called.
MyLogic.GetMyString() -> MyService.GetMyStringFromDLL() is called.
1 MarkRabjohn Dec 21 2020 at 21:45

마지막으로 NopCommerce V1.90에서 작업 한 이후로 Unity와 함께 작업 한 적이 없지만 IUnityResolver를 구현하는 인스턴스에서 Resolve를 사용하면 컨테이너에 등록한 모든 항목이 다시 표시된다는 것을 기억합니다.

따라서 기본적으로 IMyService를 등록했지만 IMyLogic도 등록해야합니다. "var logic = new MyLogic ();"대신 "var logic = resolver.Resolve (typeof (IMyLogic)); " 그런 다음 주입 된 매개 변수가 종속성 주입기에 따라 해결됩니다 (또는 누락 된 경우 적절한 오류가 발생 함).