Repository pattern with Autofac

The repository pattern is one of the most popular patterns used in the applications architecture.

With Autofac we are able to manage the dependencies and the lifecycle of the repositories in our application.

So let’s starting with the implementation of a basic respository example, then we proceed with the Autofac configurations and with the test methods.

Repository implementation

The are many choices to put into practice the repository pattern.

But this is not the main topic of this post, so we can proceed with a simple implementation:


public class Product
{
public int Code { get; set; }
public string Description { get; set; }
}

public interface IProductsRepository
{
List<Product> GetProducts();
}

public class ProductsRepository : IProductsRepository
{
private string _connectionString;
private List<Product> _products { get; set; }

public ProductsRepository(string connectionString)
{
_connectionString = connectionString;

_products = new List<Product>()
{
new Product()
{
Code = 1,
Description = "Product1"
},
new Product()
{
Code = 2,
Description = "Product2"
}
};
}

public List<Product> GetProducts()
{
return _products;
}
}

The ProductRepository implements a simple interface and has a constructor that accept a connection string parameter and populates a list of products.

In the real world the repository should use the connection string to connect to a database and retrieve the products, but in this case is easier to build an in memory list.

Now we inject this repository in the services that use it:


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 has a GetProducs method that returns the list of products if a specific token is valid.

Autofac configuration

Autofac can be organized in modules, each of witch will be registered in the container.

In this case, we can implement a module for all the objects registered as PerDependency:


public class PerDependencyModule : Module
{
protected override void Load(ContainerBuilder builder)
{
var repositoriesAssembly = Assembly.GetAssembly(typeof(ProductsRepository));
builder.RegisterAssemblyTypes(repositoriesAssembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces()
.WithParameter(
new TypedParameter(typeof(string), ConfigurationManager.ConnectionStrings["Context"].ToString())
);
}
}

By default, Autofac registers the components as per dependency, that means that a unique instance of the object will be created for each request.

With the first row we retrieve the list of the repository objects in the assembly, by checking that in the name of the class the word Repository is present.

Then we say autofac that the object shall be registered as the implemented interface; if you remember, in the constructor of the ProductService we defined the repository parameter by using the interface and not the relative concrete class.

The last part define the parameter that the repository needs, that is the connection string.

The second module that we create is the SingleInstanceModule:


public class SingleInstancesModule : Module
{
protected override void Load(ContainerBuilder builder)
{

builder.RegisterType<ProductsService>()
.AsSelf()
.SingleInstance();
}
}

We register the ProductService as single instance because we want that only one instance for this service exists in the application.

Then we register the modules in the Autofac container.

Because we want to test the configuration, we can make a BaseTest class with NUnit, and build the container in the Setup method.


[TestFixture]
public class BaseTests
{
protected IContainer containerBuilder;
protected HttpConfiguration httpConfiguration;

[SetUp]
public void Setup()
{
var builder = new ContainerBuilder();

// SINGLE INSTANCES
builder.RegisterModule(new SingleInstancesModule());

// PER DEPENDENCY
builder.RegisterModule(new PerDependencyModule());

containerBuilder = builder.Build();
}

[TearDown]
public void TearDown()
{
containerBuilder.Dispose();
}
}

With the RegisterModule method we are able to register an entire module defined.

Test methods

Here we go, now we can implement test methods to check that our configuration is correct.

First of all, we check the ProductRepository registration:


public class PerDependencyTests : BaseTests
{

[Test]
public void should_be_able_to_resolve_instance_per_dependency()
{
using (var scope = containerBuilder.BeginLifetimeScope())
{
var result = scope.Resolve<IProductsRepository>();
result.Should().NotBeNull();
}
}

[Test]
public void should_not_be_able_to_resolve_instance_per_dependency()
{
ProductsRepository repository = null;

try
{
using (var scope = base.containerBuilder.BeginLifetimeScope())
{
repository = scope.Resolve<ProductsRepository>();
repository.ShouldBeEquivalentTo(null);
}
}
catch (Exception)
{
repository.ShouldBeEquivalentTo(null);
}
}
}

For every test method we create a LifetimeScope that is useful to create a concrete instance of the repository.

In the first test method we try to resolve the IProductRepository interface, and the result is true.

In the second one, we try to resolve the concrete class, and we should not be able to do it, because, as you remember, we registered the ProductRepository as the implemented interface.

The ProductService registration test methods might look like these:


public class SingleInstanceTests: BaseTests
{

[Test]
public void should_return_the_products_list()
{
using (var scope = containerBuilder.BeginLifetimeScope())
{
var productsService = scope.Resolve<ProductsService>();
var result = productsService.GetProducts();

result.Should().NotBeNull();
result.Should().NotBeEmpty();
}
}

[Test]
public void should_is_the_same_single_instance()
{
ProductsService productsService1, productsService2;

using (var scope = containerBuilder.BeginLifetimeScope())
{
productsService1 = scope.Resolve<ProductsService>();
}

using (var scope = containerBuilder.BeginLifetimeScope())
{
productsService2 = scope.Resolve<ProductsService>();
}

ReferenceEquals(productsService1, productsService2).ShouldBeEquivalentTo(true);
}
}

The first method check that a list of products is returned.

The second one verify that for different lifetime scopes, the service instance is the same.

You can find the source code here.

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at WordPress.com

Up ↑

%d bloggers like this: