patterncsharpMinor
IoC Agnostic Test Project
Viewed 0 times
projectioctestagnostic
Problem
I've been reading a lot about IoC and DI and I still haven't understood if it's a bad practice to make your Application IoC agnostic, but seems only logical to me that it should be IoC agnostic.
Using a 4 layer approach I've coded a test project just to try and apply these concepts and this is what a came up with:
Data Layer with EF 6.1.3
UnitOfWork:
Repo(generic):
```
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using TestProject.Core.Contracts;
using TestProject.Core.Contracts.Repos;
using TestProject.Persistence.Contracts;
namespace TestProject.Persistence.Repos
{
public class Repo : IRepo where TEntity : class
{
protected readonly DbSet _entities;
public Repo(IContext context) => _entities = context.Set();
public void Add(TEntity entity) => _entities.Add(entity);
public IEnumerable Find(Expression> predicate)
{
return _entities.Where(predicate).ToList();
}
public TEntity
Using a 4 layer approach I've coded a test project just to try and apply these concepts and this is what a came up with:
Data Layer with EF 6.1.3
UnitOfWork:
using TestProject.Persistence.Contracts;
namespace TestProject.Core
{
public class UnitOfWork : IUnitOfWork
{
private readonly IContext _context;
public IRepo Customers { get; set; }
public IRepo MembershipsTypes { get; set; }
public IRepo Movies { get; set; }
public IRepo Genres { get; set; }
public UnitOfWork(
IContext context,
IRepo customers,
IRepo membershipsTypes,
IRepo movies,
IRepo genres)
{
_context = context;
Customers = customers;
MembershipsTypes = membershipsTypes;
Movies = movies;
Genres = genres;
}
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
GC.SuppressFinalize(this);
}
}
}Repo(generic):
```
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using TestProject.Core.Contracts;
using TestProject.Core.Contracts.Repos;
using TestProject.Persistence.Contracts;
namespace TestProject.Persistence.Repos
{
public class Repo : IRepo where TEntity : class
{
protected readonly DbSet _entities;
public Repo(IContext context) => _entities = context.Set();
public void Add(TEntity entity) => _entities.Add(entity);
public IEnumerable Find(Expression> predicate)
{
return _entities.Where(predicate).ToList();
}
public TEntity
Solution
Do not tie up too many classes with DI if you want code to loosely coupled with Container.
Instead, Why not have your own registration & resolver object. This way you will have to change only three classes (in given example) when you wish to change the DI container.
Keep all these classes in one assembly and call bootstrap from starting of the application, and inject register class when you need to use modules.
This way you can keep all your code indepndent of DI, and only one assembly needs to be changed.
You may need to expose more methods for different types of registrations and resolution.
Instead, Why not have your own registration & resolver object. This way you will have to change only three classes (in given example) when you wish to change the DI container.
public interface IContainerRegister
{
void Register() where TService : class, TInterface;
// not required, I needed though for WCF
IResolver GetResolver();
}
public interface IResolver
{
TService GetService();
}
internal class Resolver : IResolver
{
// change to your container choice
private readonly IUnityContainer _diContainer;
public Resolver(IUnityContainer DIContainer)
{
_diContainer = DIContainer;
}
public TService GetService()
{
return _diContainer.Resolve();
}
}
internal class ContainerRegister : IContainerRegister
{
// change to your container choice
private readonly IUnityContainer _diContainer;
public ContainerRegister(IUnityContainer diContainer)
{
_diContainer = diContainer;
}
public void Register() where TService : class, TInterface
{
// change according to your container choice
_diContainer.RegisterType();
}
public IResolver GetResolver()
{
// change according to your container choice
return _diContainer.Resolve();
}
}
internal class BootStrap
{
// change to your container choice
private UnityContainer _container = null;
public IContainerRegister Init()
{
_container = new UnityContainer();
_container.LoadConfiguration();
_container.RegisterInstance(_container);
_container.RegisterType();
_container.RegisterType();
// register your modules here using reflection
// resolve each modules and call register()
return _container.Resolve();
}
}
public abstract class BaseModule {
public BaseModule(IContainerRegister register){
_register = register;
}
public abstract void Register();
}Keep all these classes in one assembly and call bootstrap from starting of the application, and inject register class when you need to use modules.
This way you can keep all your code indepndent of DI, and only one assembly needs to be changed.
You may need to expose more methods for different types of registrations and resolution.
Code Snippets
public interface IContainerRegister
{
void Register<TInterface, TService>() where TService : class, TInterface;
// not required, I needed though for WCF
IResolver GetResolver();
}
public interface IResolver
{
TService GetService<TService>();
}
internal class Resolver : IResolver
{
// change to your container choice
private readonly IUnityContainer _diContainer;
public Resolver(IUnityContainer DIContainer)
{
_diContainer = DIContainer;
}
public TService GetService<TService>()
{
return _diContainer.Resolve<TService>();
}
}
internal class ContainerRegister : IContainerRegister
{
// change to your container choice
private readonly IUnityContainer _diContainer;
public ContainerRegister(IUnityContainer diContainer)
{
_diContainer = diContainer;
}
public void Register<TInterface, TService>() where TService : class, TInterface
{
// change according to your container choice
_diContainer.RegisterType<TInterface, TService>();
}
public IResolver GetResolver()
{
// change according to your container choice
return _diContainer.Resolve<IResolver>();
}
}
internal class BootStrap
{
// change to your container choice
private UnityContainer _container = null;
public IContainerRegister Init()
{
_container = new UnityContainer();
_container.LoadConfiguration();
_container.RegisterInstance<IUnityContainer>(_container);
_container.RegisterType<IResolver, Resolver>();
_container.RegisterType<IContainerRegister, ContainerRegister>();
// register your modules here using reflection
// resolve each modules and call register()
return _container.Resolve<IContainerRegister>();
}
}
public abstract class BaseModule {
public BaseModule(IContainerRegister register){
_register = register;
}
public abstract void Register();
}Context
StackExchange Code Review Q#157056, answer score: 2
Revisions (0)
No revisions yet.