Multi-service and multi-level dependency injection framework for .NET [ Wiki ]
IocServiceStack is open source .NET dependency injection framework. IoC container allows to add multiple services for the same contract by name and dependencies can be added at different levels. This makes the concerns of application layers separated, and configurable. So, the client-specific logic can be plugged easily or inject the specific dependencies for specific client implementations. And, it offers several ways to inject dependencies. This framework contains the main container in which there are three types of internal containers such as root container, shared and dependency container.
PM> Install-Package IocServiceStack
var container = IocServicelet.Configure(config =>
{
config.AddServices((service) =>
{
/*if namespaces are not specfied, it finds for services in entire assembly.*/
service.Namespaces = new[] { "BusinessService" };
service.Assemblies = new[] { "BusinessServiceLibrary" };
service.AddDependencies((repository) =>
{
repository.Name = "Repository";
repository.Namespaces = new[] { "RepositoryService" }; ;
repository.Assemblies = new[] { "RepositoryServiceLibrary" };
repository.AddDependencies((data) =>
{
data.Name = "Data";
data.Namespaces = new[] { "DataService" };
data.Assemblies = new[] { "DataServiceLibrary" };
});
});
//service.AddSharedServices(shared=> { shared.Assemblies = new {""} });
service.StrictMode = true;
});
//.RegisterServiceProvider(new ProxyServiceProvider());
});
//Initialization
var container = IocServicelet.Configure(config =>
{
config.AddServices((service) =>
{
service.AddDependencies((dopt) => {
dopt.Name = "DataContext"; /*Dependency factory name */
});
});
});
//Add dependencies at level - 1
container.GetRootContainer()
.Add<ICustomer, CustomerService>()
.Add<IOrder, OrderService>()
.Add<AbstractSale, OnlineSale>("Online") /*Access: var onlineSale = ServiceManager.GetService<AbstractSale>("Online"); //Get OnlineSale object */
.Add<AbstractSale, PointOfSale>("Pos"); /*Access: var posSale = ServiceManager.GetService<AbstractSale>("Pos"); //Get PointOfSale object */
//Check multiple implementations of interface -> https://github.com/rjinaga/IocServiceStack/wiki/Accessing%20service%20by%20Name
// Add dependencies at level - 2
container.GetDependencyContainer("DataContext") /* get dependency factory by name */
.Add<IDbContext>(()=>new AdventureDbContext());
IocServiceStack can map the services to their interfaces automatically, in order to work this function, set the Contract attribute to the interface and Service attribute to the class that implements the interface. ServiceInit attribute must be set to the constructor to be invoked.
namespace BusinessService
{
using IocServiceStack;
using Models;
[Contract]
public interface ICustomerService
{
void AddCustomer(Customer customer);
}
}
namespace BusinessService
{
using IocServiceStack;
using BusinessContractLibrary;
using Models;
using RepositoryService;
[Service]
public class CustomerService : ICustomerService
{
private ICustomerRepository _repository;
public CustomerService(ICustomerRepository repository)
{
_repository = repository;
}
public ICustomerRepository GetRepository()
{
return _repository;
}
public void AddCustomer(Customer customer)
{
_repository.Add(customer);
}
}
}
namespace RepositoryService
{
using IocServiceStack;
using Models;
[Contract]
public interface ICustomerRepository
{
void Add(Customer customer);
void Update(Customer customer);
void Delete(Customer customer);
Customer GetCustomer(int customerId);
}
}
namespace RepositoryService
{
using System;
using IocServiceStack;
using DataContractLibrary;
using Models;
[Service]
public class CustomerRepository : ICustomerRepository
{
public CustomerRepository(IDbContext dbcontext)
{
}
public void Add(Customer customer)
{
throw new NotImplementedException();
}
public void Delete(Customer customer)
{
throw new NotImplementedException();
}
public Customer GetCustomer(int customerId)
{
throw new NotImplementedException();
}
public void Update(Customer customer)
{
throw new NotImplementedException();
}
}
}
namespace DataService
{
using IocServiceStack;
[Contract]
public interface IDbContext
{
}
}
namespace DataService
{
using IocServiceStack;
using DataContractLibrary;
[Service]
public class AdventureDbContext : IDbContext
{
public AdventureDbContext()
{
}
}
}
var customerService = ServiceManager.GetService<ICustomer>();
You can replace with another service which is already discovered by the IocServiceStack, or add a new service.
var rootContainer = container.GetRootContainer();
/*Dependency Injection*/
rootContainer.Replace<ICustomer, CustomerService2>();
container.GetDependencyContainer("Repository").Replace<ICustomerRepository, CustomerRepository2>();
/*Add new service*/
rootContainer.Add<IPayment, PaypalPayment>();
/*setup container*/
var container = IocServicelet.CreateContainer(config=> { /* */ });
/* You can add services by calling container.Add<Interface>(()=> new Service()) */
/*set a new container to a static field */
Example.AppServiceManager.Container = container;
/* Create IoC service manager class(Eg: AppServiceManager) to access services in the container. */
namespace Example
{
using System;
public static class AppServiceManager
{
public static IocContainer Container;
public static T GetService<T>() where T : class
{
var provider = Container.ServiceProvider;
return provider.GetService<T>();
}
public static object GetService(Type contractType)
{
var provider = Container.ServiceProvider;
return provider.GetService(contractType);
}
}
}
You can build and configure service decorators globally or interface level. Decorators will be executed once the instance is constructed. It provides the flexibility to modify the object or inject concrete objects at runtime.
You can also register decorators with the isolated containers.
var configRef = IocServicelet.Configure(config =>
{
/* ..... */
config.Decorators.Add(new CustomInjectorDecorator());
}
/*use decorator*/
namespace BusinessContractLibrary
{
using IocServiceStack;
using Models;
[Contract, CustomerDecorator]
public interface ICustomer
{
string AdditionalData { get; set; }
void AddCustomer(Customer customer);
}
}
/*Implement decorator*/
namespace BusinessContractLibrary
{
using IocServiceStack;
public class CustomerDecoratorAttribute : DecoratorAttribute
{
public override void OnBeforeInvoke(ServiceCallContext context)
{
base.OnBeforeInvoke(context);
}
public override void OnAfterInvoke(ServiceCallContext context)
{
//Set Default Value
var customer = context.ServiceInstance as ICustomer;
if (customer != null)
{
customer.AdditionalData = "Gold Customer";
}
}
}
}
IocServiceStack finds the dependencies of root service from the immediate dependency sub container, if it could not be found then system searches in the shared sub container. Shared container provides flexibility to add common dependencies across the system.
container.GetSharedContainer()
.Add<ICustomerRepository, CustomerRepository>() /*this depends on the IDbContext*/
.Add<IDbContext>(()=> new AdventureDbContext());