Container.GetInstance(Type) 在使用 WcfOperationLifestyle 时抛出 ActivationException

Container.GetInstance(Type) when using WcfOperationLifestyle throws ActivationException

我有一个使用 SimpleInjector 的 WebAPI 服务。我使用 AsyncScopedLifestyle 为我的范围依赖项设置了此设置,这些依赖项之一是我的 Entity Framework DataContext。我服务中的许多事情都依赖于 DataContext,并且它通常使用构造函数注入注入到我的 MediatR 处理程序中 - 这很有效。另外,我有几个区域需要在给定类型(作为字符串)的情况下创建对象的实例,因此我创建了一个配置有参考的自定义激活器 class (ResolvingActivator)到 Container.GetInstance(Type):

在我的容器中 bootstrap 代码:

ResolvingActivator.Configure(container.GetInstance);

然后我可以使用以下方法创建对象:

ResolvingActivator.CreateInstance<T>(typeName)

当我使用 WebAPI 时,上面的代码运行良好。


该项目的另一部分是使用 WCF 的遗留 API。我将其实现为一个转换层,我将旧消息格式转换为新消息格式,然后将消息发送给调解器;然后,我将响应(以新格式)翻译回旧格式,并将 return 那些回复给调用者。因为我需要在我的 WCF 服务中访问调解器,所以我将其注入到它们的构造函数中,并使用 SimpleInjector.Integration.Wcf 包让 SimpleInjector 提供的 SimpleInjectorServiceHostFactory 构建服务实例。我还创造了一种混合生活方式,因此我可以为我的 WebAPI 和 WCF 服务使用同一个容器:

container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
            new AsyncScopedLifestyle(),
            new WcfOperationLifestyle());

这对于某些调用来说效果很好,但是当调用最终调用我的 ResolvingActivator class 时,我得到一个 ActivationException 抛出,并显示以下消息:

The DataContext is registered as 'Hybrid Async Scoped / WCF Operation' lifestyle, but the instance is requested outside the context of an active (Hybrid Async Scoped / WCF Operation) scope.

因为我只在进行 WCF 调用时收到此错误,我想知道我的配置是否有问题。简而言之,这将起作用:

public class SomeClass
{
    private readonly DataContext db;

    public SomeClass(DataContext db)
    {
        this.db = db;
    }

    public bool SomeMethod() => this.db.Table.Any();
}

但这不会:

public class SomeClass
{    
    public bool SomeMethod()
    {
        // Code behind is calling container.GetInstance(typeof(DataContext))
        var db = ResolvingActivator.CreateInstance<DataContext>();

        return db.Table.Any();
    }
}

有什么地方出错了吗?

编辑:这里是来自 ActivationException 的堆栈跟踪:

   at SimpleInjector.Scope.GetScopelessInstance[TImplementation](ScopedRegistration`1 registration)
   at SimpleInjector.Scope.GetInstance[TImplementation](ScopedRegistration`1 registration, Scope scope)
   at SimpleInjector.Advanced.Internal.LazyScopedRegistration`1.GetInstance(Scope scope)
   at lambda_method(Closure )
   at SimpleInjector.InstanceProducer.GetInstance()
   at SimpleInjector.Container.GetInstance(Type serviceType)
   at Service.Core.ResolvingActivator.CreateInstance(Type type) in Service.Core\ResolvingActivator.cs:line 43
   at Service.Core.ResolvingActivator.CreateInstance(String typeName) in Service.Core\ResolvingActivator.cs:line 35
   at Service.Core.ResolvingActivator.CreateInstance[TService](String typeName) in Service.Core\ResolvingActivator.cs:line 69

这里有完整的堆栈跟踪:https://pastebin.com/0WkyHGKv

仔细检查堆栈跟踪后,我可以得出结论:异步。

幕后的 WcfOperationLifestyle 依赖于 WCF 的 OperationContext.Current 属性,但是这个 属性 具有线程亲和性并且不与异步操作一起流动。这是必须在 Simple Injector 的集成库中修复的东西;它目前根本不支持异步。

相反,在开始和结束新异步作用域的处理程序周围包装一个装饰器。这使您不必同时使用 WcfOperationLifestyle。查看 ThreadScopedCommandHandlerProxy<T> 实现 here 以了解如何执行此操作(但改用 AsyncScopedLifestyle)。