问题
For reference, I have a service that I want to register as a singleton in the unity container. I want this service to have the IEventAggerator injected into the service somehow, either by property or constructor injection.
public class BeckhoffService: IProgrammableLogicController
{ ...}
and I'll either want this:
[Dependency]
public IEventAggregator eventAggregator{get;set;}
or in the constructor:
BeckhoffService(IEventAggregator eventAggregator)
My issue comes when I register this service in the unity container as a singleton.
In my module Initialize, these are the options I've tried:
IProgrammableLogicController controllerSingleton = new BeckhoffService();
_container.RegisterInstance<IProgrammableLogicController>(controllerSingleton);
The above correctly registers as a singleton, but the Dependencies in "controllerSingleton" do not get resolved.
_container.RegisterInstance<IProgrammableLogicController>(new BeckhoffService());
The above resolves the dependencies in "new BeckhoffService()" but the container does not return the singleton instance when it is resolved.
I was able to implement it by passing the IEventAggregator into the Beckhoff service manually without the Unity Container injecting into the service directly, but that seemed sort of ugly:
IProgrammableLogicController controllerSingleton = new BeckhoffService(_container.Resolve<IEventAggregator>());
_container.RegisterInstance<IProgrammableLogicController>(controllerSingleton);
Is there a better or more preferred way of accomplishing what I want? Thanks!
回答1:
Which dependencies?
IProgrammableLogicController controllerSingleton = new BeckhoffService();
_container.RegisterInstance<IProgrammableLogicController>(controllerSingleton);
In your first example, you initialize BeckhoffService()
yourself and using a parameterless constructor, so of course you won't get anything injected.
Same for your second example. You initialize the object yourself, not through the IoC container.
You either have to initialize the class yourself and pass the dependencies yourself, or you have to register the types to your IoC container and have the container resolve it!
For example:
container.Register<IProgrammableLogicController, BeckhoffService>(new ContainerControlledLifetimeManager());
and then resolve it with
IProgrammableLogicController controller = container.Resolve<IProgrammableLogicController>();
The ContainerControlledLifetimeManager
lifetime manager is Unity equivalent of singleton (technically pretty close to it), as for the lifetime of the container, always the same instance will be returned. Since your composition root lies closing to the App start (at least it should, if not you may get issues), the main IoC container usually lives as long as the App lives.
Unity also allows creating of child containers, if you need singletons for a specific operation chain, you'd create a child container and within this operation the IoC would return always same instance. Once the operation is finished, you dispose the container and next operation chain will instantiate the singletons again for the duration of that operation etc.
Usually you use RegisterInstance
for types which aren't resolvable (i.e. 3rd party library) or need configuration (for example if you want to configure an instance of a logger service). Then you'd instantiate it yourself, configure it and register it to the IoC as instance. This is valid for configuration during the object graph setup.
If you have classes, which only require dependencies and no configuration/initialization, you should use the RegisterType
method.
If you have classes, which require a certain parameter or dependency at run time, you need to implement an "Abstract Factory" and create/resolve the instance via a method which requests the parameter. This avoids that you forget to call an objects configuration methods.
Bad:
// ctor
public MyClass(IMyDependency dep) {
dep.RuntimeDependencyValue = 42; // Bad if RuntimeDependencyValue is required for the class to work
// or
dep.Initialize(42);
}
Better:
public MyClass(IMyDependencyFactory depFactory) {
IMyDependency dep = depFactory.Create(42);
}
Second one is better, because abstract the resolve/creation plus initialization behind the factory class. Now you can't miss to initialize it with important parameters, as the only way to create it is by a method which force you to pass the required parameter.
来源:https://stackoverflow.com/questions/29565473/injecting-a-property-into-a-singleton-service-in-prism-unity-mvvm