【问题标题】:Autofac resolves components with mixed scopeAutofac 解析具有混合范围的组件
【发布时间】:2011-10-24 22:01:42
【问题描述】:

我在 asp.net 中使用 Autofac 2.5,我遇到了一个问题,即生命周期范围的组件被解析为单实例组件的依赖关系,从而破坏了我的线程安全。这是注册的问题,但我认为 Autofac 认为这是违规行为并会引发异常。

    private class A{}

    private class B
    {
        public B(A a){}
    }

    [Test]
    [ExpectedException()]
    public void SingleInstanceCannotResolveLifetimeDependency()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<A>()
            .InstancePerLifetimeScope();
        builder.RegisterType<B>()
            .SingleInstance();

        using (var container = builder.Build())
        {
            using (var lifetime = container.BeginLifetimeScope())
            {
                //should throw an exception
                //because B is scoped singleton but A is only scoped for the lifetime
                var b = lifetime.Resolve<B>();
            }
        }
    }

如果发生这种情况,有没有办法让 Autofac 抛出依赖解析异常?

更新 即使这是 Autofac 的正确行为 - SingleInstance 只是 Root 生命周期范围内的 - 它在 Web 环境中可能存在潜在危险。确保所有开发人员都获得正确的注册可能会很痛苦。这是 Autofac 的一个小型扩展方法,它检查实例查找以确保生命周期范围内的实例不会在根范围内得到解析。我知道它帮助我们从 Web 项目中清除了生命周期问题。

    public static class NoLifetimeResolutionAtRootScopeExtensions
{
    /// <summary>
    /// Prevents instances that are lifetime registration from being resolved in the root scope
    /// </summary>
    public static void NoLifetimeResolutionAtRootScope(this IContainer container)
    {
        LifetimeScopeBeginning(null, new LifetimeScopeBeginningEventArgs(container));
    }

    private static void LifetimeScopeBeginning(object sender, LifetimeScopeBeginningEventArgs e)
    {
        e.LifetimeScope.ResolveOperationBeginning += ResolveOperationBeginning;
        e.LifetimeScope.ChildLifetimeScopeBeginning += LifetimeScopeBeginning;
    }

    private static void ResolveOperationBeginning(object sender, ResolveOperationBeginningEventArgs e)
    {
        e.ResolveOperation.InstanceLookupBeginning += InstanceLookupBeginning;
    }

    private static void InstanceLookupBeginning(object sender, InstanceLookupBeginningEventArgs e)
    {
        var registration = e.InstanceLookup.ComponentRegistration;
        var activationScope = e.InstanceLookup.ActivationScope;

        if (registration.Ownership != InstanceOwnership.ExternallyOwned
            && registration.Sharing == InstanceSharing.Shared
            && !(registration.Lifetime is RootScopeLifetime)
            && activationScope.Tag.Equals("root"))
        {
            //would be really nice to be able to get a resolution stack here
            throw new DependencyResolutionException(string.Format(
                "Cannot resolve a lifetime instance of {0} at the root scope.", registration.Target))
        }
    }
}

只需在创建容器时应用它,当生命周期范围内的服务在根范围内解析时,您将得到抛出异常。

container.NoLifetimeResolutionAtRootScope();

【问题讨论】:

    标签: .net dependency-injection autofac


    【解决方案1】:

    是的 - 您需要命名子作用域,并将组件 A 与其明确关联。否则,如您所见,将在根(容器)范围内创建一个 A 实例。

    // Replace `A` registration with:
    builder.RegisterType<A>().InstancePerMatchingLifetimeScope("child");
    

    还有……

    // Replace scope creation with:
    using (var lifetime = container.BeginLifetimeScope("child")) {
    

    【讨论】:

    • 谢谢,我花了一段时间才弄清楚单个实例只是根生命周期范围内的。
    • 我用一个小的扩展方法更新了我的问题,以便为这些情况抛出异常。如果在 ResolveOperation 上暴露“_activationStack”会很好,然后我可以抛出更多有用的信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 2017-06-09
    • 1970-01-01
    • 2022-11-02
    • 2010-09-09
    相关资源
    最近更新 更多