Search code examples
c#dependency-injectionautofaclifetime-scoping

Instance per matching lifetime scope, with default?


I'd like to have an instance per matching lifetime scoped registration in Autofac, but occasionally need to request an instance from a global container (where there is no matching lifetime scope). In scenarios where no matching lifetime scope exists, I want to give a top-level instance instead of throwing an exception.

Is this possible?


Solution

  • I think you'd better extend Autofac by introducing a new lifetime option. I took the Autofac sources and modified them a bit:

    public static class RegistrationBuilderExtensions
    {
        public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InstancePerMatchingOrRootLifetimeScope<TLimit, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> builder, params object[] lifetimeScopeTag)
        {
            if (lifetimeScopeTag == null) throw new ArgumentNullException("lifetimeScopeTag");
            builder.RegistrationData.Sharing = InstanceSharing.Shared;
            builder.RegistrationData.Lifetime = new MatchingScopeOrRootLifetime(lifetimeScopeTag);
            return builder;
        }
    }
    
    public class MatchingScopeOrRootLifetime: IComponentLifetime
    {
        readonly object[] _tagsToMatch;
    
        public MatchingScopeOrRootLifetime(params object[] lifetimeScopeTagsToMatch)
        {
            if (lifetimeScopeTagsToMatch == null) throw new ArgumentNullException("lifetimeScopeTagsToMatch");
    
            _tagsToMatch = lifetimeScopeTagsToMatch;
        }
    
        public ISharingLifetimeScope FindScope(ISharingLifetimeScope mostNestedVisibleScope)
        {
            if (mostNestedVisibleScope == null) throw new ArgumentNullException("mostNestedVisibleScope");
    
            var next = mostNestedVisibleScope;
            while (next != null)
            {
                if (_tagsToMatch.Contains(next.Tag))
                    return next;
    
                next = next.ParentLifetimeScope;
            }
    
            return mostNestedVisibleScope.RootLifetimeScope;
        }
    }
    

    Just add these classes to your project and register you component as:

    builder.RegisterType<A>.InstancePerMatchingOrRootLifetimeScope("TAG");
    

    I haven't tried it myself, but it should work.