enriquein
enriquein

Reputation: 1038

Configuring lifetime scopes in autofac when used as ServiceStack's IoC

I'm currently using AutoFac as the DI container for our ServiceStack web services app. I'm able to configure the wiring and everything, but after reading the section on Scopes, I'm at a loss at which scope would be best to use when registering my components. In our particular case, I think a PerHttpRequest scope would be OK since (please correct me if im wrong) I would want to dispose the dependencies as soon as the request ends.

My question is, how do I set this up in the container? I can't seem to find the "PerHttpRequest" lifetime scope within the included methods in autofac. I'm also unsure if ServiceStack does some kind of automagic to do this for me behind the scenes.

I'm using Autofac 3.0.1 on ServiceStack 3.9.35 on .Net 4 (running as a regular ASP host, not MVC). I'm also using the class described here as the IContainer adapter.

Upvotes: 3

Views: 2957

Answers (4)

Alexey Zimarev
Alexey Zimarev

Reputation: 19630

Update 2015-11-25: I changed the implementation by using global request and response filters. I put both ServiceStack V3 and V4 solutions into this repository and both versions are available as nuget packages.

I solved this problem by opening a new scope in Application_BeginRequest and disposing in Application_EndRequest. In the container adapter I check if this scope exists and use it, if not, I use the container. This allows using .InstancePerRequest() registration scope.

Described with gists here.

Upvotes: 2

killspice
killspice

Reputation: 391

I wanted to avoid the overhead of the dependency on MVC, so the first answer didn't quite work for me.

Instead I used Funq to register a PerRequest ILifetimeScope, and resolve the ILifetimeScope in the ConatinerAdaptor before resolving the dependency.

public class AutofacLifetimeScopeIocAdapter : IContainerAdapter
{
    private readonly Container _requestContainer;

    public AutofacLifetimeScopeIocAdapter(Funq.Container requestContainer)
    {
        _requestContainer = requestContainer;
    }


    public T Resolve<T>()
    {
        var currentContainer = _requestContainer.Resolve<ILifetimeScope>();

        return currentContainer.Resolve<T>();
    }

    public T TryResolve<T>()
    {
        var currentContainer = _requestContainer.Resolve<ILifetimeScope>();

        T result;

        if (currentContainer.TryResolve<T>(out result))
        {
            return result;
        }

        return default(T);
    }

}

Then initialise with this

_autofacContainerRoot = builder.Build();
        IContainerAdapter adapter = new AutofacLifetimeScopeIocAdapter(container);

        container.Register<ILifetimeScope>((c) => _autofacContainerRoot.BeginLifetimeScope())
            .ReusedWithin(ReuseScope.Request);

        container.Adapter = adapter;

Then cleanup with

public override void OnEndRequest()
    {
        var currentContainer = _container.Resolve<ILifetimeScope>();
        currentContainer.Dispose();

        base.OnEndRequest();
    } 

This seems to behave as required for Autofac - SingleInstance, InstancePerDependency, and now InstancePerLifetimeScope which is perRequest.

Mythz response on the HostContext.Instance.Items collection can likely be used to remove the need for the

var currentContainer = _container.Resolve<ILifetimeScope>();

resolution, which should improve performance.

Upvotes: 5

jlew
jlew

Reputation: 10591

I think I have figured out how to make this work (using Autofac 2.6, which I am stuck on right now.) It involves using the following adapter and the Autofac.Mvc3 package:

public class AutofacIocAdapter : IContainerAdapter
{
    private readonly IContainer _autofacRootContainer;
    private readonly Container _funqContainer;

    public AutofacIocAdapter(IContainer autofacRootContainer, Container funqContainer)
    {
        // Register a RequestLifetimeScopeProvider (from Autofac.Integration.Mvc) with Funq
        var lifetimeScopeProvider = new RequestLifetimeScopeProvider(autofacRootContainer,null);
        funqContainer.Register<ILifetimeScopeProvider>(x => lifetimeScopeProvider);
        // Store the autofac application (root) container, and the funq container for later use
        _autofacRootContainer = autofacRootContainer;
        _funqContainer = funqContainer;
    }

    public T Resolve<T>()
    {           
        return ActiveScope.Resolve<T>();
    }

    public T TryResolve<T>()
    {
        T result;
        if (ActiveScope.TryResolve(out result))
        {
            return result;
        }
        return default(T);
    }

    private ILifetimeScope ActiveScope
    {
        get
        {
            // If there is an active HttpContext, retrieve the lifetime scope by resolving
            // the ILifetimeScopeProvider from Funq.  Otherwise, use the application (root) container.
            return HttpContext.Current == null
                        ? _autofacRootContainer
                        : _funqContainer.Resolve<ILifetimeScopeProvider>().GetLifetimeScope();
        }
    }
}

Steps to implement:

  1. Add the Autofac.Mvc3 NuGet package to your web project (NOTE: does not matter that your project isn't using MVC. The solution might be slightly different with Autofac 3, which cannot use Mvc3 integration.)
  2. Follow the ServiceStack IoC page in hooking up a custom IContainerAdapter for Autofac, using the following implementation

Upvotes: 4

mythz
mythz

Reputation: 143339

Note the RequestScope in ServiceStack's IOC only refers to ServiceStack's built-in Funq IOC.

To use RequestScope in another IOC Container like AutoFac you generally need to notify AutoFac at the end of the request so it can clean up all its request-scoped instances. To do this, ServiceStack provides the AppHostBase.OnEndRequest() hook you can override to get execute custom logic at the end of each request.

I'm not familiar with how AutoFac's custom lifetime scope works but more details about it can be found in:

Other info that might be useful for managing instances in ServiceStack is that every instance in put in the HostContext.Instance.Items dictionary or disposable added to HostContext.Instance.TrackDisposable are automatically disposed at the end of each request.

Upvotes: 2

Related Questions