Autofac终身管理

Eya*_*nik 6 asp.net-mvc lifetime autofac

我正在开发一个支持外部插件的ASP.NET MVC项目,现在,我正在从Unity转移到Autofac,我需要包装Autofac的生命周期对象,以便插件不必在Unity I中引用它可以做点什么.

public sealed class UnityScopeFactory : IDependencyScopeFactory
{
    private HttpRequestScope _httpRequest;

    private SingletonScope _singleton;

    private TransientScope _transient;

    public IDependencyScope HttpRequest()
    {
        return _httpRequest ?? (_httpRequest = new HttpRequestScope());
    }

    public IDependencyScope Singleton()
    {
        return _singleton ?? (_singleton = new SingletonScope());
    }

    public IDependencyScope Transient()
    {
        return _transient ?? (_transient = new TransientScope());
    }

    private class HttpRequestScope : IDependencyScope
    {
        public object CreateScope()
        {
            return new HttpPerRequestLifetimeManager();
        }
    }

    private class SingletonScope : IDependencyScope
    {
        public object CreateScope()
        {
            return new ContainerControlledLifetimeManager();
        }
    }

    private class TransientScope : IDependencyScope
    {
        public object CreateScope()
        {
            return new TransientLifetimeManager();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我在Autofac中做了类似的事情,但是我不确定这是否是正确的方法,我查看了Autofac的RegistrationBuilder(不幸的是)内部,我想出了这个.

public class AutofacScopeFactory : IDependencyScopeFactory
{
    private HttpRequestScope _httpRequest;

    private SingletonScope _singleton;

    private TransientScope _transient;

    public IDependencyScope HttpRequest()
    {
        return _httpRequest ?? (_httpRequest = new HttpRequestScope());
    }

    public IDependencyScope Singleton()
    {
        return _singleton ?? (_singleton = new SingletonScope());
    }

    public IDependencyScope Transient()
    {
        return _transient ?? (_transient = new TransientScope());
    }

    private class HttpRequestScope : IDependencyScope
    {
        public object CreateScope()
        {
            return new CurrentScopeLifetime();
        }
    }

    private class SingletonScope : IDependencyScope
    {
        public object CreateScope()
        {
            return new RootScopeLifetime();
        }
    }

    private class TransientScope : IDependencyScope
    {
        public object CreateScope()
        {
            return new CurrentScopeLifetime();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

另外,在我使用它之后,如何使用它将它传递给ContainerBuilder?

在Unity中我可以做这样的事情.

public sealed class UnityDependencyContainer : IDependencyContainer
{
    private readonly IUnityContainer _container;

    public UnityDependencyContainer()
    {
        _container = new UnityContainer()
    }

    public void Register<TContract, TImplementation>(IDependencyScope scope) where TImplementation : TContract
    {
        LifetimeManager manager = scope.CreateScope() as LifetimeManager;

        if (manager != null)
        {
            _container.RegisterType<TContract, TImplementation>(manager);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如何将IComponentLifetime的实例传递给方法链?这是死路一条吗?

public class AutofacContainer : IDependencyContainer
{
    private static readonly ContainerBuilder Builder;

    static AutofacContainer()
    {
        Builder = new ContainerBuilder();
    }

    public void RegisterType<TContract, TImplementation>(IDependencyScope scope) where TImplementation : TContract
    {
        IComponentLifetime manager = scope.CreateScope() as IComponentLifetime;

        if (manager != null)
        {
            Builder.RegisterType<TImplementation>().As<TContract>();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Tra*_*lig 10

Autofac不会像您所描述的那样将范围分开,因此您可能会尝试将方形钉固定在圆孔中.

Autofac范围更加分层.任何生命周期范围都可以产生子瞬态范围.例如,您可能会看到......

  • 容器/根寿命
    • HttpRequest范围
      • 小任务特定的瞬态范围

您可以"标记"范围并将组件注册到特定的命名/标记范围 - 这就是HttpRequest范围的工作方式.它被标记为"特殊标识符".

解析对象时,它确定哪个生命周期范围拥有它.解析发生在最嵌套的范围内.在上面的层次结构中,您可以从小任务特定的瞬态范围中解析项目,无论它们是单例,请求范围还是其他.单例解析后,它将搜索生命周期范围堆栈并自动将对象的"所有权"分配给根生存期范围.当每个请求项被解析时,它会使用特殊的"HTTP请求"标识符在堆栈中搜索生命周期范围,并在那里分配所有权.工厂范围的项目在当前生命周期范围内得到解析.

注意:该讨论过于简单化了. 有文档解释Autofac站点上的生命周期范围机制.

重点是,我看到上面设计中的一些东西并没有像Autofac那样真正地"jive".

DependencyScopeFactory无法创建自己的瞬态或HttpRequest范围.有特定的生命周期管理组件可以启动和结束HttpRequest范围,因此您需要使用这些组件; 没有"全局"瞬态范围,所以你不能真正创建一个.

假设您正在使用MVC,HttpRequest范围看起来更像......

public ILifetimeScope HttpRequestScope
{
  get { return AutofacDependencyResolver.Current.RequestLifetime; }
}
Run Code Online (Sandbox Code Playgroud)

对于瞬态范围没有模拟,因为它的使用应该是内联的:

using(var transientScope = parentScope.BeginLifetimeScope())
{
  // Do stuff and resolve dependencies using the transient scope.
  // The IDisposable pattern here is important so transient
  // dependencies will be properly disposed at the end of the scope.
}
Run Code Online (Sandbox Code Playgroud)

注册组件时,不要将它们"注册到生命周期范围内".您实际上将它们注册到组件注册表中,组件注册的一部分包括有关组件解析后的生命周期的所有权信息.

var builder = new ContainerBuilder();

// This component is factory-scoped and will be "owned" by whatever
// lifetime scope resolves it. You can resolve multiple of these
// in a single scope:
builder.RegisterType<FirstComponent>().As<ISomeInterface>();

// This component is a singleton inside any given lifetime scope,
// but if you have a hierarchy of scopes, you'll get one in each
// level of the hierarchy.
builder.RegisterType<SecondComponent>().InstancePerLifetimeScope();

// This component will be a singleton inside a specifically named
// lifetime scope. If you try to resolve it in a scope without that
// name, it'll search up the scope stack until it finds the scope
// with the right name. If no matching scope is found - exception.
builder.RegisterType<ThirdComponent>().InstancePerMatchingLifetimeScope("scopename");

// This is a per-HTTP-request component. It's just like the
// above InstancePerMatchingLifetimeScope, but it has a special
// tag that the web integration knows about.
builder.RegisterType<FourthComponent>().InstancePerHttpRequest();
Run Code Online (Sandbox Code Playgroud)

如果您正在尝试创建容器/注册不可知接口,则不需要"生命周期范围管理器" - 相反,您需要传递一些指示预期生命周期范围的参数并执行相应的注册语法(上面)根据传入的参数.

再次建议您查看该文档.

此外,如果您使用Unity,Autofac会有一个Enterprise Library Configurator软件包,允许您以Unity样式配置Autofac(因为这就是EntLib喜欢做的事情).这可能是要检查的东西.

如果您根本不需要使用Unity语法... 我建议您继续使用原生Autofac方式.试图使一个容器看起来像另一个容器是一个非常痛苦的努力.

假设您的插件位于单独的程序集中或其他任何组件中,您可以轻松利用一些不错的程序集扫描语法以及Autofac模块,并以这种方式连接您的插件.