C# 在自定义TypeFormatter中使用RegisterWebapireRequest时SimpleInjector.ActivationException

C# 在自定义TypeFormatter中使用RegisterWebapireRequest时SimpleInjector.ActivationException,c#,dependency-injection,asp.net-web-api2,formatter,simple-injector,C#,Dependency Injection,Asp.net Web Api2,Formatter,Simple Injector,我使用定制的JsonMediaTypeFormatter来扩展请求中的数据。但是当我使用GetInstance方法时,格式化程序会抛出一个异常。我做错了什么 Global.asax: // Create the container as usual. var container = new Container(); // Register your types, for instance using the RegisterWebApiRequest // extension from the

我使用定制的JsonMediaTypeFormatter来扩展请求中的数据。但是当我使用GetInstance方法时,格式化程序会抛出一个异常。我做错了什么

Global.asax:

// Create the container as usual.
var container = new Container();

// Register your types, for instance using the RegisterWebApiRequest
// extension from the integration package:
container.RegisterWebApiRequest<TestDataContext>();

// This is an extension method from the integration package.
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

container.Verify();

GlobalConfiguration.Configuration.DependencyResolver =
    new SimpleInjectorWebApiDependencyResolver(container);

// Here your usual Web API configuration stuff.
GlobalConfiguration.Configuration.Formatters.Add(new StringFormatter(container));
//像往常一样创建容器。
var container=新容器();
//注册您的类型,例如使用RegisterWebapireRequest
//集成包的扩展:
container.RegisterWebApiRequest();
//这是集成包中的扩展方法。
容器.RegisterWebApp控制器(全局配置.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver=
新的SimpleInjectorWebApidencyResolver(容器);
//这里是您常用的Web API配置资料。
GlobalConfiguration.Configuration.Formatters.Add(新的StringFormatter(容器));
格式化程序(经过简化,可用于新的MVC Web Api项目):

公共类StringFormatter:JsonMediaTypeFormatter
{
私有只读容器_容器;
公共字符串格式化程序(容器)
{
_容器=容器;
支持的媒体类型。添加(
新的MediaTypeHeaderValue(“application/vnd.mywebapplication+json”);
}
公共覆盖布尔CanReadType(类型)
{
返回false;
}
公共重写bool CanWriteType(类型)
{
return(type==typeof(IEnumerable)| | type==typeof(string));
}
public override void WriteToStream(类型类型、对象值、流writeStream、,
System.Text.Encoding(有效编码)
{
//抛出SimpleInjector.ActivationException
var dataContext=_container.GetInstance();
var result=dataContext.GetText();
type=result.GetType();
值=结果;
base.WriteToStream(类型、值、writeStream、有效编码);
}
}
这是异常消息:

TestDataContext类型的注册委托引发了异常。 TestDataContext已注册为“Web API请求”,但 该实例是在Web API请求的上下文之外请求的

有点凌乱的堆栈跟踪:

at SimpleInjector.InstanceProducer.GetInstance() 
at SimpleInjector.Container.GetInstance[TService]() 
at WebApplication4.Formatter.StringFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding) in d:\UserProfiles\luuk\Documents\Visual Studio 2013\Projects\WebApplication4\WebApplication4\Formatter\StringFormatter.cs:line 35 
at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content) 
at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()"

at SimpleInjector.Scope.GetScopelessInstance[TService,TImplementation](ScopedRegistration'2 registration) 
at SimpleInjector.Scope.GetInstance[TService,TImplementation](ScopedRegistration'2 registration, Scope scope) 
at SimpleInjector.Advanced.Internal.LazyScopedRegistration'2.GetInstance(Scope scope) 
at DynamicInstanceProducer2.GetInstance(Object[] constants) 
at SimpleInjector.CompilationHelpers.<>c__DisplayClass1b'1.
位于SimpleInjector.InstanceProducer.GetInstance()
在SimpleInjector.Container.GetInstance[TService]()
在d:\UserProfiles\luuk\Documents\Visual Studio 2013\Projects\WebApplication4\WebApplication4\Formatter\StringFormatter.WriteToStream(类型、对象值、流writeStream、编码有效编码)中的WebApplication4.Formatter.StringFormatter.WriteToStream(有效编码):第35行
位于System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(类型类型、对象值、流writeStream、HttpContent)
在System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(类型类型、对象值、流writeStream、HttpContent内容、TransportContext TransportContext、CancellationToken CancellationToken)----引发异常的上一个位置的堆栈结束跟踪--
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
在System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification(任务任务)中
在System.Runtime.CompilerServices.TaskAwaiter.GetResult()中
在System.Web.Http.WebHost.HttpControllerHandler.d_u1b.MoveNext()中
在SimpleInjector.Scope.GetScopelessInstance[TService,TImplementation](ScopedRegistration'2注册)
在SimpleInjector.Scope.GetInstance[TService,TImplementation](ScopedRegistration'2注册,Scope范围)
位于SimpleInjector.Advanced.Internal.LazyScopedRegistration'2.GetInstance(范围)
位于DynamicInstanceProducer2.GetInstance(对象[]常量)
在SimpleInjector.compileHelpers.c__中显示Class1B'1。

经过一些调试之后,我发现Web API处理
类型格式化程序的方式有些奇怪。它在创建请求的
idependencycoscope
之后,但在处理该作用域之前调用
WriteToStream
。但尽管在启动之间调用了
WriteToStream
idependencycoscope
的末尾,它不会在与Web API请求的其余部分相同的执行上下文中调用

这意味着对于SimpleInjector而言,在该时间点没有请求,因为SimpleInjector使用.NET的执行上下文跟踪
SimpleInjector.Scope

这可能是Web API中的一个缺陷,但可能是Web API中的设计缺陷。可能原因是类型格式化程序只包含基本逻辑,而不与当前请求或某些后端数据库交互。这听起来很合理,但并不能解决您的问题

解决这个问题的一个简单方法是显式创建一个
ExecutionContextScope

public override void WriteToStream(Type type, object value, Stream writeStream,
    System.Text.Encoding effectiveEncoding)
{
    using (container.BeginExecutionContextScope())
    {
        var dataContext = _container.GetInstance<TestDataContext>(); 

        var result = dataContext.GetText();
        type = result.GetType();
        value = result;

        base.WriteToStream(type, value, writeStream, effectiveEncoding);
    }
}
public override void WriteToStream(类型、对象值、流writeStream、,
System.Text.Encoding(有效编码)
{
使用(container.BeginExecutionContextScope())
{
var dataContext=_container.GetInstance();
var result=dataContext.GetText();
type=result.GetType();
值=结果;
base.WriteToStream(类型、值、writeStream、有效编码);
}
}
WebApiRequestLifestyle
实际上只是
ExecutionContextScopeLifestyle
的一个实用包装器,它只是寻找一个活动的
ExecutionContextScope
。因此,通过明确地启动这样一个范围(使用
BeginExecutionContextScope
)您可以确保有一个可以解析
TestDataContext
的范围

我认为其他DI框架也会遇到同样的问题。要么这些框架也会使用执行上下文,要么它们允许您将活动解析范围传递给调用方,这两种方法在这种方法中都是不可能的
public override void WriteToStream(Type type, object value, Stream writeStream,
    System.Text.Encoding effectiveEncoding)
{
    using (container.BeginExecutionContextScope())
    {
        var dataContext = _container.GetInstance<TestDataContext>(); 

        var result = dataContext.GetText();
        type = result.GetType();
        value = result;

        base.WriteToStream(type, value, writeStream, effectiveEncoding);
    }
}