简体   繁体   中英

How to add Dependency Injection (DI) using Unity MVC 4 in a Non Controller Class

So I am using Unity MVC-4 for achieving Dependency Injection and it works great with my Controller classes but as soon as I try to inject in my non controller class, I get the NullReferenceException and I can see that my injected objects are not initialized by the framework. I will give you the corresponding classes that I am using:

Controller class (DI works):

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;
    }
}

And if I do the same thing in a non controller method (DI does not work here), I get a 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;
    }
}

My BootStrapper.cs class looks like:

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)
    {

    }

}

If you see above in the line container.RegisterType<IMyService, MyService>(); , the interface and its concrete implementation is in a separate module.

And my Global.asax.cs is:

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

How can I inject the IMyService in MyLogic class?

Use attribute [InjectionConstructor] to tell the Unity that the MyLogic class is dependent on an object which is to be injected in the constructor:

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

Actually the [InjectionConstructor] is recommended to use when the injected class contains more than one constructor. Therefore, the attribute is used to resolve the disambiguation. It was just my hypothesis why the Unity cannot resolve the required type, because of the question code does not contain all part of the code. But in the test code below the [InjectionConstructor] attribute not needed, because of only one constructor is declared.

Here it is the test code.

The IMyService interface definition:

public interface IMyService
{
    string GetMyStringFromDLL();
}

The ILogic interface definition:

public interface IMyLogic
{
    string GetMyString();
}

The MyLogic implementation:

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;
    }
}

The MyService implementation:

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

The Bootstrapper initialization:

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;
    }
}

The Home controller implementation:

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} );
    }
}

And finally when default action method of the Home controller executed the following two lines are displayed:

MyService.GetMyStringFromDLL() is called.
MyLogic.GetMyString() -> MyService.GetMyStringFromDLL() is called.

I haven't worked with Unity since I last did some work on NopCommerce V1.90, however I do remember that whatever you register in your container does come back if you use Resolve on an instance implementing IUnityResolver.

So basically, you registered IMyService, but you'd also have to register IMyLogic - then instead of doing "var logic = new MyLogic();", you'd do "var logic = resolver.Resolve(typeof(IMyLogic));" and then your injected parameters will be resolved according to the dependency injector (or you'd get the proper errors if they were missing).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM