3

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.

enriquein
  • 1,048
  • 1
  • 12
  • 28

4 Answers4

5

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.

killspice
  • 391
  • 3
  • 4
4

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
jlew
  • 10,491
  • 1
  • 35
  • 58
  • Can't wait to get back home to give this a shot. Thanks for the pointers! – enriquein Mar 15 '13 at 19:17
  • Just wanted to drop in and add that your solution almost worked. I think this is because I'm using Autofac 3 and MVC4 integration. The only thing that I had to change was to add a parameter to GetLifetimeScope: return HttpContext.Current == null ? _autofacRootContainer : _funqContainer.Resolve().GetLifetimeScope(x => new ContainerBuilder() ); Not sure if there's a better or more correct way to do this, but it seems to work like a charm in my end. – enriquein May 15 '13 at 19:16
2

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.

Community
  • 1
  • 1
mythz
  • 141,670
  • 29
  • 246
  • 390
  • 1
    Thanks for always being around to answer our questions! I'm currently behind schedule on this project so I went back to using Funq, which was already working fine for us anyway. When I get some free time next sprint I'll probably look into it for educational purposes in case I ever need to actually switch to Autofac because of project requirements. There's still some internal stuff I can't seem to figure out with Autofac, which is understandable since I picked it up this week for the first time. Again, thanks so much for always being so helpful to the community! – enriquein Feb 12 '13 at 19:42
  • np :) hoped the info helped. I've never needed anything more than Funq myself, which is a great option. Whenever I need something more complicated I prefer to add the behavior in code which I find a lot more easier to reason about, then prodding Heavy-Featured IOC's for advanced features. – mythz Feb 12 '13 at 20:19
  • I'm trying to do this too. The trick is that resolution must happen against an autofac child container. It's not clear to me how to stash one in Items at the very beginning of the request (before the service object has been instantiated) and then retrieve it when needed (inside the IContainerAdapter.) – jlew Mar 13 '13 at 20:39
2

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.

Alexey Zimarev
  • 17,944
  • 2
  • 55
  • 83