Hinzufügen von Dependency Injection (DI) mit Unity MVC 4 in einer Nicht-Controller-Klasse
Ich verwende Unity MVC-4, um Dependency Injection zu erreichen, und es funktioniert hervorragend mit meinen Controller
Klassen. Sobald ich jedoch versuche, in meine Nicht-Controller-Klasse zu injizieren, erhalte ich das NullReferenceException
und kann sehen, dass meine injizierten Objekte nicht vom Framework initialisiert werden . Ich werde Ihnen die entsprechenden Klassen geben, die ich benutze:
Controller
Klasse (DI funktioniert):
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;
}
}
Und wenn ich dasselbe in einer Nicht-Controller-Methode mache (DI funktioniert hier nicht), bekomme ich Folgendes 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;
}
}
Meine BootStrapper.cs
Klasse sieht aus wie:
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)
{
}
}
Wenn Sie oben in der Zeile sehen container.RegisterType<IMyService , MyService>();
, befindet sich die Schnittstelle und ihre konkrete Implementierung in einem separaten Modul.
Und mein Global.asax.cs
ist:
protected void Application_Start()
{
Bootstrapper.Initialise();
AreaRegistration.RegisterAllAreas();
GlobalFilters.Filters.Add(new OfflineActionFilter());
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Wie kann ich das IMyService
in der MyLogic
Klasse injizieren ?
Antworten
Verwenden Sie das Attribut [InjectionConstructor] , um der Unity mitzuteilen, dass die MyLogic
Klasse von einem Objekt abhängig ist, das in den Konstruktor eingefügt werden soll:
[InjectionConstructor]
public MyLogic(IMyService myService)
{
_myService = myService;
}
Tatsächlich [InjectionConstructor]
wird empfohlen, das zu verwenden, wenn die injizierte Klasse mehr als einen Konstruktor enthält. Daher wird das Attribut verwendet, um die Begriffsklärung aufzulösen. Es war nur meine Hypothese, warum der Unity
erforderliche Typ nicht aufgelöst werden kann, da der Fragencode nicht den gesamten Teil des Codes enthält. Im folgenden Testcode wird das [InjectionConstructor]
Attribut jedoch nicht benötigt, da nur ein Konstruktor deklariert ist.
Hier ist es der Testcode.
Die IMyService
Schnittstellendefinition:
public interface IMyService
{
string GetMyStringFromDLL();
}
Die ILogic
Schnittstellendefinition:
public interface IMyLogic
{
string GetMyString();
}
Die MyLogic
Implementierung:
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;
}
}
Die MyService
Implementierung:
public class MyService : IMyService
{
public string GetMyStringFromDLL()
{
return "MyService.GetMyStringFromDLL() is called.";
}
}
Die Bootstrapper
Initialisierung:
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;
}
}
Die Home
Controller-Implementierung:
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} );
}
}
Und schließlich werden bei der Home
Ausführung der Standardaktionsmethode des Controllers die folgenden zwei Zeilen angezeigt:
MyService.GetMyStringFromDLL() is called.
MyLogic.GetMyString() -> MyService.GetMyStringFromDLL() is called.
Ich habe seit meiner letzten Arbeit an NopCommerce V1.90 nicht mehr mit Unity gearbeitet. Ich erinnere mich jedoch, dass alles, was Sie in Ihrem Container registrieren, zurückkommt, wenn Sie Resolve für eine Instanz verwenden, die IUnityResolver implementiert.
Im Grunde haben Sie IMyService registriert, aber Sie müssten auch IMyLogic registrieren - anstatt "var logic = new MyLogic ();" auszuführen, würden Sie "var logic = resolver.Resolve (typeof (IMyLogic)) ausführen. "" und dann werden Ihre injizierten Parameter entsprechend dem Abhängigkeitsinjektor aufgelöst (oder Sie würden die richtigen Fehler erhalten, wenn sie fehlen würden).