AutoFac
Scopes & Lifetimes


Scopes

    • There is no global 'scope' context
      • Registrations will only be resolved from the ILifetimeScope returned by BeginLifetimeScope.

using (ILifetimeScope parentScope = CreateContainer())
{
    using (ILifetimeScope childScope1 = parentScope.BeginLifetimeScope(b => 
               b.RegisterType<MyType>().SingleInstance()))
    using (ILifetimeScope childScope2 = parentScope.BeginLifetimeScope(b => 
               b.RegisterType<MyType>().SingleInstance()))
    {
        MyType result1 = childScope1.Resolve<MyType>();
        MyType result2 = childScope2.Resolve<MyType>();
 
        result1.ShouldNotReferTo(result2);
    }
}

Scopes

    • Child scopes do not affect parent scopes. 
    • Child scopes inherit registrations from parent scopes. 
      • Similar as class inheritance, don't create a child scope unless you need what's in the parent scope 

Scopes

    • Must be disposed! 
                         
    • Scopes have DisposalManagers - you can register a scope to be disposed when another scope is disposed.
    • Watch out for scopes shared between threads.

When to create scopes

    • Almost never. Ideally there should be only one resolve, which means only one scope. 
    • In reality, we need to create a scope per resource view.
    • We also have scopes for printing.

Lifetimes

Default is InstancePerDependency.
[Test]
public void InstancePerDependency_NewInstanceCreatedEveryTime()
{
    using (ILifetimeScope scope = CreateContainer(builder => 
           builder.RegisterType<MyType>()))
    {
        MyType instance1 = scope.Resolve<MyType>();
        MyType instance2 = scope.Resolve<MyType>();
 
        instance1.ShouldNotReferTo(instance2);
    }
}

Lifetimes

SingleInstance is scoped to where it's registered.
[Test]
public void SingleInstance_IsScopedToWhereRegistrationOccurs()
{
    using (ILifetimeScope outerScope = CreateContainer(b => b.RegisterType<MyType>()))
    {
        using (ILifetimeScope middleScope = outerScope.BeginLifetimeScope(b => 
                   b.RegisterType<MyType>().SingleInstance()))
        {
            using (ILifetimeScope innerScope = middleScope.BeginLifetimeScope())
            {
                MyType outerResult = outerScope.Resolve<MyType>();
                MyType innerResult = innerScope.Resolve<MyType>();
                MyType middleResult = middleScope.Resolve<MyType>();
 
                outerResult.ShouldNotReferTo(middleResult);
                innerResult.ShouldReferTo(middleResult);
            }
        }
    }
}

Lifetimes

InstancePerLifetimeScope will be one per scope.
[Test]
public void InstancePerLifetimeScope_OneInstancePerScope()
{
    using (ILifetimeScope outerScope = CreateContainer(b => 
              b.RegisterType<MyType>().InstancePerLifetimeScope()))
    {
        using (ILifetimeScope innerScope = outerScope.BeginLifetimeScope())
        {
            MyType outerInstance1 = outerScope.Resolve<MyType>();
            MyType outerInstance2 = outerScope.Resolve<MyType>();
            MyType innerInstance = innerScope.Resolve<MyType>();
 
            outerInstance1.ShouldReferTo(outerInstance2);
            innerInstance.ShouldNotReferTo(outerInstance1);
        }
    }
}

When to use non-default lifetimes

    • Almost never - only if state needs to be shared between consumers. 
    • Don't worry about performance - there's no logic in your constructors, right?

RIGHT‽

Registrations

    • How do you find out where something is registered?
    • Press Shift-Alt-F12, then type module

    • Agent Mulder plugin for R#

Registrations

What happens if there's no explicit registration?

Registrations

    • Explicit registrations are best
      • .As<Interface>() not .AsImplementedInterfaces()
      • RegisterAssemblyTypes only for interfaces with many implementations
          • ICommand
          • Controller
    • Last registration for an interface wins
      • Great for explicit registrations
      • Not so great for automatic registrations

Registrations

Avoid confusing errors & behaviour
  • Don't register types in scopes that shouldn't need them
    • IResourceRepository
  • Separate modules by 'module' of code
    • Resource modules


Don't be this dog

AutoFac

By soxtoby

AutoFac

  • 28