Services lifetime scope with Autofac

Basically when we resolve a component with Autofac, we could register the object instance in the root container; this is not the best practice, because these components will never be disposed as long as the container lives, that normally is the lifetime of the application.

Then, the root container will hold the references until the application shutdown, and this could be cause memoty leaks.

A better approach is the using of the lifetime scopes, that help us to define an area where the service can be shared with other components and disposed at the end.

Let’s start defining the classes to be used as services in the Autofac configuration.

Services

We can use two simple class, a CustomerService class and an OrdersService:


public class CustomerService
{
public CustomerService() { }
}


public class OrdersService
{
private ITokenService _tokenService;

public OrdersService(ITokenService tokenService)
{
this._tokenService = tokenService;
}

}

The OrdersService accepts in the constructor an ITokenService and we have an implementation of that:


public class PerDependencyTokenService : ITokenService
 {
 private Guid _token { get; set; }

public Guid GetToken()
 {
 if (_token == Guid.Empty)
 _token = Guid.NewGuid();

return _token;
 }
 }

Now we can define the services registration, let’s start creating the Autofac modules.

Modules

First of all, we need to register the PerDependencyTokenService and we must identify it in order to distinguish this service from the others that implements the ITokenService interface:


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

builder.RegisterType<PerDependencyTokenService>()
 .AsSelf()
 .AsImplementedInterfaces()
 .Keyed<ITokenService>("perDependencyTokenService");
 }
 }

We registered the service as Keyed, and we identified that with a specific tag.

Now we can register the other services:


public class PerLifetimeScopeModule : Module
 {
 protected override void Load(ContainerBuilder builder)
 {
 builder.RegisterType<OrdersService>()
 .AsSelf()
 .InstancePerLifetimeScope()
 .WithParameter(new ResolvedParameter(
 (pi, ctx) => pi.ParameterType == typeof(ITokenService),
 (pi, ctx) => ctx.ResolveKeyed<ITokenService>("perDependencyTokenService")
 ));

// PER MATCHING LIFETIMESCOPE
 builder.RegisterType<CustomerService>()
 .AsSelf()
 .InstancePerMatchingLifetimeScope("scope1");
 }

}

OrderService is registered as InstancePerLifetimeScope, so an instance of this component will be unique in a specific scope.

We specify the Parameter ITokenService as well, and we tell to Autofac to resolve this with a specific key; so we are able to specify the concrete class that implements the ITokenService interface.

The second registration is about the CustomerService; this registration is slightly different from the first one, because we want to resolve the CustomerService only for the lifetime scopes that has a specific name.

Now we are going to implement the test methods that will use the services.

Test methods

The first step is register the module in the Autofac container:

builder.RegisterModule(new PerLifetimeScopeModule());

Then we can implement the test methods:

public class InstancePerLifetimeScopeTests : BaseTests
{
[Test]
public void should_is_not_the_same_instance_for_different_lifetime_scopes()
{
OrdersService ordersService1, ordersService2;

using (var scope = containerBuilder.BeginLifetimeScope())
{
ordersService1 = scope.Resolve<OrdersService>();
}

using (var scope = containerBuilder.BeginLifetimeScope())
{
ordersService2 = scope.Resolve<OrdersService>();
}

ReferenceEquals(ordersService1, ordersService2).ShouldBeEquivalentTo(false);
}

[Test]
public void should_not_be_able_to_resolve_instance_per_lifetime_scope()
{
CustomerService customerService1 = null, customerService2 = null;

try
{
using (var scope = containerBuilder.BeginLifetimeScope())
{
customerService1 = scope.Resolve<CustomerService>();

using (var scope1 = containerBuilder.BeginLifetimeScope("scope1"))
{
customerService2 = scope.Resolve<CustomerService>();
}

customerService1.ShouldBeEquivalentTo(null);
}
}
catch (Exception)
{
customerService1.ShouldBeEquivalentTo(null);
}
}

[Test]
public void should_be_able_to_resolve_instance_per_lifetime_scope()
{
CustomerService customerService1, customerService2;

using (var scope = containerBuilder.BeginLifetimeScope("scope1"))
{
customerService1 = scope.Resolve<CustomerService>();

using (var scope1 = containerBuilder.BeginLifetimeScope())
{
customerService2 = scope.Resolve<CustomerService>();
}
}

ReferenceEquals(customerService1, customerService2).ShouldBeEquivalentTo(true);
}
}

In the first method, we create two different lifetime scopes and we check that the two objects have not the same reference.

In the second one, we should not be able to resolve the CustomerService for a generic lifetime scope, because we registered this service for a scope named scope1.

So this row:

customerService1 = scope.Resolve<CustomerService>();

will throw a DependencyResolutionException.

Instead in the third method will be able to resolve the service, because we try to create an instance in a LifetimeScope named scope1; and of course, this service will be single instance for every lifetime scope that match the name.

You can find the source code here.

 

Advertisements
Services lifetime scope with Autofac

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s