Autofac is a popular and very useful IoC container, a tool that help us to manage the dependency injection in our application.
What we want from a IoC container is the ability to instantiate the objects needed in different contexts and situations and define configurations, without worry about who and when instantiate these objects.
Of course, the target application need to be ready to host an IoC container, that means all the components of the application will need to be able to receive their dependencies as inputs.
Moving on, one of a common cases where we use an IoC container is to manage a singleton service.
The old school did solve this situation without an IoC container, but defining the service as static and using it directly in the objects that depends upon it.
With Autofac this service will be defined as a non static object and injected in the constructor as dependence.
This is the first of series of post that I hope help to understand the power of Autofac and to discover more in detail a bunch of features useful for our applications.
Application architecture
Lets starting with the development of a example application that will using Autofac.
In this application we need to implement and share a singleton service; the scope of this service is generate a token and provide it to the dependent services.
So, the token service implement an interface:
public interface ITokenService { Guid GetToken(); }
And the implementation is like this:
public class SingletonTokenService : ITokenService { private Guid _token { get; set; } public Guid GetToken() { if (_token == Guid.Empty) _token = Guid.NewGuid(); return _token; } }
This is a very simple piece of code so far.
Now you can implement the ProductService, that need to use TokenService:
public class ProductsService { private IProductsRepository _productsRepository; private ITokenService _tokenService; public ProductsService(IProductsRepository productsRepository, ITokenService tokenService) { this._productsRepository = productsRepository; this._tokenService = tokenService; } public List<Product> GetProducts() { List<Product> products = new List<Product>(); if (_tokenService.GetToken() != Guid.Empty) products = _productsRepository.GetProducts(); return products; } }
The service receives in the constructor the dependencies objects and assign them to private objects.
The GetProducts method check if the token is valid and returns the list of products.
Now we need to configure Autofac in order to provide the services.
Autofac container
Autofac has a container builder that we use to define the rules for the objects instantiation:
var builder = new ContainerBuilder(); builder.RegisterType<SingletonTokenService>() .AsSelf() .AsImplementedInterfaces() .SingleInstance(); builder.RegisterType<ProductsService>() .AsSelf() .SingleInstance(); containerBuilder = builder.Build();
You can notice SingleInstance option, that means these services are singleton; furthermore, the SingleTokenService has the option AsImplementedInterface that allow to resolve all the dependencies that refer to the interface implemented by the service (in the constructor of the ProductService we refer to the interface, not to the implemented class).
Resolve the service
The last step is resolve the ProductService.
We expect that once resolved, will exist only a single instance of the service; we can make a simple test method using NUnit.
public void should_is_the_same_instance() { ProductsService productsService1, productsService2; using (var scope = this.containerBuilder.BeginLifetimeScope()) { productsService1 = scope.Resolve<ProductsService>(); } using (var scope = this.containerBuilder.BeginLifetimeScope()) { productsService2 = scope.Resolve<ProductsService>(); } object.ReferenceEquals(productsService1, productsService2).ShouldBeEquivalentTo(true); }
In order to simulate two request, we use the BeginLifeTimeScope method, that create a separate scope for the instances; with the Resolve method we tell to Autofac to resolve and create an instance of a specific object, with the rules specified in the container.
In the last row we check that the two objects have reference equality.
You can find the source code here.
Leave a Reply