Reputation: 41
I have two separate projects... One project is using Simple Injector and the other Unity. From the simple injector project, I am attempting to register the interface/implementation of a class located within the project using Unity for its DI. I can successfully do this and gain access to the class but anything marked as a Unity [Dependency] within that class does not resolve. I can register those dependencies to the Simple Injector container but it loses it once crossing into the class using Unity.
Example:
Project1 (using Simple Injector)
public class StartUp {
var container = new Container();
container.RegisterSingleton(typeof(IGenericRepo<>), typeof(GenericRepo));
container.RegisterSingleton<IService, Service>();
//more code below etc...
}
public class TestController
{
private readonly IService service;
public TestController(IService service)
{
this.service = service;
}
public void TestMethod()
{
var test = service.GetEverything();
}
}
Project2 (using Unity)
public class Service : IService
{
[Dependency]
public IGenericRepo<ServiceObj> _serviceRepo { private get; set; }
public IQueryable<ServiceObj> GetEverything()
{
return _serviceRepo.Get();
}
}
With the example above, I can get to the GetEverything method within Project 2, but then the _serviceRepo dependecy is null. Is there a way for it to know to use the registered GenericRepo<> from Project1?
Is this possible to do?
Thank you! Ryan
Upvotes: 0
Views: 970
Reputation: 5540
If I understand correctly Project 2 is some shared project which is used in other projects which use Unity for Dependency Injection. Unity uses property injection in this case by annoting the property with the DependencyAttribute
.
Simple Injector is capable of doing property injection. Property injection however should only be used for optional dependencies. And as you're running into a NullReferenceException
this dependency is not optional!
So you should move the IGenericRepo<ServiceObj>
to the constructor of IService
. This makes it clear to users of IService
that it needs a repository to function correctly. This becomes especially useful when you would unittest IService
as the constructor will in this case clearly communicates that it needs a repository.
By moving the dependency to the constructor Simple Injector will inject the repository correctly or throw an ActivationException
if the configuration is not valid.
You can test, and I recommend doing this, by calling container.Verify()
as you can read here: Verify the container’s configuration. This will make the application to fail fast.
If project 2 can't be refactored or for some other compelling reason constructor injection is not an option, Simple Injector does support property injection. It does however not support this out-of-the-box. One of the design principles of Simple Injector is to never fail silently and therefore only Explicit property injection is advised. This will gives the container the opportunity to use its Diagnostic Services and fail fast if the configuration is invalid.
As you can read in the referenced documentation, there are 2 ways of doing it property injection:
container.RegisterInitializer()
IPropertySelectionBehavior
Option 2 will let Simple Injector check the dependencies using the Diagnostics Services automatically. When verifying all 'initializers' are executed also, but the code in lambda isn't checked for lifestyles etc.
Simple Injector does not encourage its users to take a dependency on the container and it therefore does not contain any Atrributes
which you can use out-of-the-box such as Unity has the DependencyAttribute
.
So you have 2 options here:
IPropertySelectionBehavior
to search for the Unity DependencyAttribute
Attribute
in project 2 and annotate _serviceRepo
which this custom attribute also.The only difference between 1 and 2 is which attribute is searched for.
If you can't touch project 2, option 2 isn't possible. Implementing IPropertySelectionBehavior
is straightforward:
// custom attribute only for option 1
public class ImportAttribute : Attribute { }
class UnityDependencyPropertySelectionBehavior : IPropertySelectionBehavior
{
public bool SelectProperty(Type type, PropertyInfo prop)
{
return prop.GetCustomAttributes(typeof(DependencyAttribute)).Any();
}
}
You can configure the container using this custom IPropertySelectionBehavior
by:
container.Options.PropertySelectionBehavior =
new UnityDependencyPropertySelectionBehavior();
To summarize:
Move the dependency to the constructor as it is not a optional dependency. In other words use constructor injection!
If there are compelling reasons not to do this implement IPropertySelectionBehavior
Upvotes: 1