Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning different components in different scopes with Autofac

Tags:

c#

autofac

I have two scopes, one nested inside the other. When I resolve a particular service, I would like one component to be resolved in one root scope and a different one in the child scope. Is there an easy way of doing this?

I have managed to get something working using a factory class that determines what the current scope is and then returning the appropriate instance:

IContainer BuildContainer()
{
    var builder = new ContainerBuilder();

    // ...
    builder.RegisterType<FooInParentScope>().AsSelf();
    builder.RegisterType<FooInChildScope>().AsSelf();
    builder.RegisterType<FooFactory>().AsImplementedInterfaces();
    builder.Register<IFoo>(c => c.Resolve<IFooFactory>().GetFoo()).InstancePerLifetimeScope();
    // ...
}


class FooFactory : IFooFactory
{
    private readonly ILifetimeScope m_scope;

    public FooFactory(ILifetimeScope scope)
    {
        m_scope = scope;
    }

    public IFoo GetFoo()
    {
        if (m_scope.Tag == "ParentScope")
            return m_scope.Resolve<FooInParentScope>();
        else
            return m_scope.Resolve<FooInChildScope>();
    }
}

class FooInParentScope : IFoo
{
}

class FooInChildScope : IFoo
{
}

There are a number of issues with this approach:

  1. I have to add an extra class (or 2 - not sure if the IFooFactory is really necessary)
  2. The code above does not cope with other scopes that are nested in ParentScope. I can fix this by casting the scope to Autofac.Core.Lifetime.LifetimeScope and examining the ParentLifetimeScope property, but that is probably not a particularly safe thing to do.
like image 468
John Hall Avatar asked Jan 23 '13 13:01

John Hall


1 Answers

You may register FooInParentScope in root container as SingleInstance. And when creating inner lifetimescope add registration for FooInChildScope as SingleInstance (override registration).

builder.RegisterType<FooInParentScope>().As<IFoo>.SingleInstance();
var container = builder.Build();

var childScope = container.BeginLifetimeScope(innerBuilder =>
    {
        // override registration for IFoo in child lifetime scope:
        innerBuilder.RegisterType<FooInChildScope>().As<IFoo>().SingleInstance();
    });

FooInParentScope fooInParentScope = (FooInParentScope) container.Resolve<IFoo>();
FooInChildScope fooInChildScope = (FooInChildScope) childScope.Resolve<IFoo>();
like image 156
Nicolay Velizhanin Avatar answered Sep 19 '22 16:09

Nicolay Velizhanin