I'm trying to register multiple implementation of single interface, but I would like to avoid using named type registration. Let's say I'm having following code:
public interface IStorage { ... }
public class DocumentStorage : IStorage { ... }
public class ImageStorage : IStorage { ... }
public interface IRepository { ... }
public class DocumentRepository : IRepository
{
public DocumentRepository(IStorage storage /*, ... and other dependencies */) { ... }
}
And doing all Unity IoC registration on single file. Rest of application does not have access to container (+ service locator pattern is big no no in my code)
Registering this would then look like this:
container.RegisterType<IStorage, DocumentStorage>("document");
container.RegisterType<IStorage, ImageStorage>("image");
container.RegisterType<IRepository, DocumentRepository>(
new InjectionFactory((c, t, s) => new DocumentRepository(
c.Resolve<IStorage>("document") /*, ... resolve other deps here */)));
And here is lying my laziness issue - I really don't want to write resolution of all dependencies this way - this makes IoC hassle. I would have to go trough all registrations depending on one of IStorage implementations and resolve all other dependencies manually.
I was thinking of turned-around solution by registering DocumentStorage resolved by DocumentRepository - which I'm not able to figure out, and moreover, it is putting dependency on another side of "equation" ("register type for being injected to another type" (instead of "register type and let it be resolved if something depends on it")).
Is there any other way how to make registration easier? (I'm not focusing on factory here - I could imagine other non-factory-able usages requiring similar way of registering dependencies)
Thanks for any advice :)
Related
I'm using unity to implement Dependency Injection in my .NET Web Api app.
Here is the relevent part of my WebApiCongig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
AppDependancyRegistry.Register(container);
config.DependencyResolver = new UnityResolver(container);
}
}
And here is my AppDependancyRegistry class
public static class AppDependancyRegistry
{
public static void Register(UnityContainer container)
{
container.RegisterType(typeof(IBaseRepository<>), typeof(BaseRepository<>));
//container.RegisterTypes( AllClasses.FromLoadedAssemblies(), WithMappings.FromMatchingInterface, WithName.Default);
}
}
I have mapped the Generic Repositores but I couldnt get through with registering the Manager classes to its interfaces. I dont want to map every one of Manager classes Manaually.
I have commented the part I have done from all the research. I just want a confirmation, this is how I do it as I cant get my App running now without doing some more of stuff
My manager classes:interfaces looks like
DutyManager: IDutyManager
UserDetailManager:IUserDetailManager
etc. Thanks in Advance
You will need, at some point, to register each of them. However, if you don't want to manually do each and every one of them, what you could "basically" do is, by reflection, load the assembly, iterate over every interface, check how many classes implement that interface, if there is only one, register the interface to that class as an unnamed registration.
Why unnamed? Well, named registration are useless unless you actually use the name in the registration, or in the ResolvedParameter constructor, and since you're not "hand crafting" the registrations, you wouldn't refer to them most likely.
Don't forget though that in your case, since the interface and the classes are generics, you'll need to check the ParameterType too.
I found the solution to this qn. Using Unity we can directly Map all classes to respecive Interfaces by using
container.RegisterTypes( AllClasses.FromLoadedAssemblies(), WithMappings.FromMatchingInterface, WithName.Default);
Here, Unity maps by convention where they map like this
DutyManager: IDutyManager
UserDetailManager:IUserDetailManager
I've read the question Ioc/DI - Why do I have to reference all layers/assemblies in application's entry point?
So, in a Asp.Net MVC5 solution, the composition root is in the MVC5 project (and having a DependencyInjection assembly in charge of all the registrations does not make sense).
Within this picture, it is not clear to me what is the better approach among the following.
Approach 1
The concrete implementations are public class ... and all registrations clauses are centralized within the composition root (e.g. in one or more files under a CompositionRoot folder). MVC5 project must reference all the assemblies providing at least one concrete implementation to be bound. No library references the DI library. MVC project can contain interfaces to be bound with no drawbacks.
Approach 2
The concrete implementations are internal class .... Each library exposes a DI 'local' configuration handler. For example
public class DependencyInjectionConfig {
public static void Configure(Container container) {
//here registration of assembly-provided implementations
//...
}
}
which is up to register its own implementations. The composition root triggers registrations by calling all the Configure() methods, just one for each project. MVC5 project must then reference all the assemblies providing at least one concrete implementation to be bound. Libraries must reference the DI library. In this case, the MVC5 project cannot contain interfaces (otherwise there would be a circular reference): a ServiceLayer assembly would be needed to hold public interfaces to be bound.
Approach 3
Same as Approach 2, but local configuration modules are discovered dynamically through assembly reflection (by convention?). So MVC5 project has not to reference libraries. MVC project can contain interfaces and can be referenced by libraries. Libraries must reference the DI library.
What is the best practice here? Is there some other better possibility?
EDIT 1 (2016-12-22)
Thanks to received answers, I published this github project describing the best solution I found so far.
EDIT 2 (2018-09-09)
This answer provides an interesting option.
EDIT 3 (2020-12-29)
Finally, I came up with a complete solution, packaged in the form of a WebApi application template. I published this solution on GitHub HERE. This approach, not only gives a clear understanding about where DI rules have to be put, but also suggests to setup the application according to SOLID principles and CQRS pattern. The commit history of this project has been structured to have educational purposes.
EDIT 4 (2023-01-31)
The repository linked above publishes an article describing the solution as well.
I typically like to encapsulate these types of things into each project. So for example I might have the following. (This is an extremely simplified example, and I'll use the AutoFac in this example, but I'd imagine all DI frameworks have something like the following).
Common area for just POCOs and Interfaces.
// MyProject.Data.csproj
namespace MyProject.Data
{
public Interface IPersonRepository
{
Person Get();
}
public class Person
{
}
}
Implementation of Repositories and Data Access
// MyProject.Data.EF.csproj
// This project uses EF to implement that data
namespace MyProject.Data.EF
{
// internal, because I don't want anyone to actually create this class
internal class PersonRepository : IPersonRepository
{
Person Get()
{ // implementation }
}
public class Registration : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register<PersonRepository>()
.As<IPersonRepository>()
.IntancePerLifetimeScope();
}
}
}
Consumer
// MyPrject.Web.UI.csproj
// This project requires an IPersonRepository
namespace MyProject.Web.UI
{
// Asp.Net MVC Example
internal class IoCConfig
{
public static void Start()
{
var builder = new ContainerBuilder();
var assemblies = BuildManager.GetReferencedAssemblies()
.Cast<Assembly>();
builder.RegisterAssemblyModules(assemblies);
}
}
}
So the Dependencies look like:
MyProject.Data.csproj
- None
MyProject.Data.EF.csproj
- MyProject.Data
MyProject.Web.UI.csproj
- MyProject.Data
- MyProject.Data.EF
In this setup, the Web.UI cannot know anything about what is registered nor for what reason. It only knows that the EF project has implementations but can't access them.
I can drop EF for say Dapper extremely easily as each project encapsulates it's own implementations and registration.
If I was adding unit tests and had an InMemoryPersonRepository, how would I swap out the PersonRepository for my InMemoryPersonRepository?
Assuming we ignore any business logic layer and have an MVC Controller directly access our Data Accessor, my code might look like:
public class MyController
{
private readonly IPersonRepository _repo;
public MyController(IPersonRepository repo)
{
_repo = repo;
}
public IActionResult Index()
{
var person = _repo.Get();
var model = Map<PersonVM>(person);
return View(model);
}
}
Then a test using nSubstitute Might look like:
public class MyControllerTests
{
public void Index_Executed_ReturnsObjectWithSameId
{
// Assign
var repo = Substitute.For<IPersonRepository>();
var expectedId = 1;
repo.Get().Returns(new Person { Id = expected });
var controller = new MyController(repo);
// Act
var result = controller.Index() as ActionResult<PersonVM>;
// Assert
Assert.That(expectedId, Is.EqualTo(result.Value.Id));
}
You've identified a real problem. (One could say it's a good problem to have.) If entry application Areferences B, B references C, and B and/or C require some DI registration, that makes A (your entry application) responsible for knowing enough about the details of B and C to register all the dependencies.
The solution is to have a separate assembly that handles composing all of the registrations for B and C. A references that, and it provides all of the container configuration that A needs to use B and C.
The benefits are
A doesn't know more about B and C than it should
Neither A, B, nor C have to be tied to one particular DI framework like Unity or Windsor.
Here's an example. This is an event bus class that works best with a DI container. But in order to use it you shouldn't have to know all about the dependencies it needs to register. So for Windsor I created a DomainEventFacility. You just call
_container.AddFacility<DomainEventFacility>();
and all of the dependencies are registered. The only thing you register are your event handlers.
Then if I want to use the same event bus library with a different DI container like Unity I can just create some similar assembly to handle the same configuration for Unity.
I have a windsor container and windsor doesnt inject my property. The curious thing is with ServiceA the dependency is resolved but not with the component.
Container.AddFacility<WcfFacility>();
Container.Register(Component.For<PublisherService>().AsWcfService());
Container.Register(Component.For<IExecutionProgram>().ImplementedBy<ExecutionProgram>());
Container.Register(Component.For<IValidationProgram>().Instance(Factory.CreateProgramA()));
Container.Register(Component.For<RunnerService>().AsWcfService());
This is my Factory (All the Dependencies implement the same interface and all SubDependencies implement an other shared Interface):
public static class Factory{
public static IValidationProgram CreateProgramA(){
var program = new ValidationProgram(
new DependencyA(
new SubDependencyA(),
new SubDependencyB(),
),
new DependencyB()
);
}
}
In my RunnerService the IExecutionProgram, Property will be resolved.
In my IValidationProgram, I created the IExecutionProgram will not be resolved.
Properties are public in both Implementations.
What did I do wrong?
EDIT:
I added the factory. These Dependencies are all Interfaces and I need specific implementations for a program. So in general I would like to switch easily between programA or programB. I looked into type Facilities like Marwijn supposed, but I cant get the hang of it. How do I use it in my case?
I have a host application which provides a plugin interface that can be implemented by plugins. When initializing plugins the host app passes in the Structuremap registry so the plugin can register things
public interface IAppPlugin
{
void Initialize(IRegistry configure);
}
public class CatPlugin : IAppPlugin
{
public void Initialize(IRegistry configure)
{
configure.For<IFilter<IPet>>()
.Add<CatFilter<IPet>>();
}
}
In my host app I have an implementation of IPet, FeralCat and I want to get from structuremap any filters
ObjectFactory.TryGetInstance<IFilter<FeralCat>>
I was hoping this would return me the CatFilter filter registered by my plugin, but it doesnt (which makes sense really, I havent registered a matching type)
My plugin doesnt know about the FeralCat, how can I configure structuremap to return the CatFilter ?
You should take a look at Advanced StructureMap: connecting implementations to open generic types, it might be useful in your case.
But for your specific code:
var container = new Container();
container.Configure(
x =>
{
x.For(typeof(IPet)).Use(typeof(FeralCat));
x.For(typeof(IFilter<>)).Use(typeof(CatFilter<>));
});
var instances = container.GetAllInstances<IFilter<FeralCat>>();
Will give you an instance of CatFilter<FerelCat>.
Using Castle Windsor, I want to configure a generic service with a type parameter; and have it implemented by a known concrete type that implements the service with a specific type as the generic parameter. Expressed as a unit test, I would like to get the following to work:
[TestClass]
public class WindsorTests
{
[TestMethod]
public void ResolveGenericEntity_Test()
{
WindsorContainer container = ConfigureContainer();
IEntity<string> entity = container.Resolve<IEntity<string>>();
Assert.IsNotNull(entity);
}
private WindsorContainer ConfigureContainer()
{
WindsorContainer container = new WindsorContainer();
container.AddComponent("entity", typeof(IEntity<>), typeof(ConcreteEntity));
return container;
}
}
public interface IEntity<T> { }
public class ConcreteEntity : IEntity<string> {}
This test fails with the following exception:
System.InvalidOperationException:
WindsorGenericsTest.ConcreteEntity is
not a GenericTypeDefinition.
MakeGenericType may only be called on
a type for which
Type.IsGenericTypeDefinition is true.
Now, I have found a post here describing the same problem. The poster describes how this can be resolved by changing the DefaultGenericHandler.ResolveCore method. However, I don't feel like changing the Castle code itself and running on a custom build.
Does anyone know how I can resolve this problem without modifying the Castle Windsor source code ? I am happy to implement a facility to support this, if that is what is needed.
Will it work if you change the line in ConfigureContainer to this?
container.AddComponent("entity", typeof(IEntity<string>), typeof(ConcreteEntity));