SimpleInjector.在自定义TypeFormatter中使用RegisterWebApiRequest时出现A
本文关键字:RegisterWebApiRequest 自定义 TypeFormatter SimpleInjector | 更新日期: 2023-09-27 18:05:14
我使用自定义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));
格式化器(简化后可以与新的MVC Web Api项目一起使用):
public class StringFormatter : JsonMediaTypeFormatter
{
private readonly Container _container;
public StringFormatter(Container container)
{
_container = container;
SupportedMediaTypes.Add(
new MediaTypeHeaderValue("application/vnd.mywebapplication+json"));
}
public override bool CanReadType(Type type)
{
return false;
}
public override bool CanWriteType(Type type)
{
return (type == typeof (IEnumerable<string>) || type == typeof (string));
}
public override void WriteToStream(Type type, object value, Stream writeStream,
System.Text.Encoding effectiveEncoding)
{
// Throws SimpleInjector.ActivationException
var dataContext = _container.GetInstance<TestDataContext>();
var result = dataContext.GetText();
type = result.GetType();
value = result;
base.WriteToStream(type, value, writeStream, effectiveEncoding);
}
}
这是异常消息:
类型TestDataContext的注册委托抛出了一个异常。TestDataContext被注册为"Web API Request"方式,但是在Web API请求的上下文之外请求实例。
位混乱stacktrace:
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.
经过一些调试后,我发现Web API处理TypeFormatter
的方式有些奇怪。它在创建请求的IDependencyScope
之后,但在处置该作用域之前调用WriteToStream
。但是,尽管WriteToStream
在IDependencyScope
的开始和结束之间被调用,但它不是在与Web API请求的其余部分相同的执行上下文中被调用。
这意味着简单注入器在那个时间点没有请求,因为简单注入器使用。net的执行上下文来跟踪SimpleInjector.Scope
类。
这可能是Web API的bug,但也可能是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);
}
}
WebApiRequestLifestyle
实际上只是ExecutionContextScopeLifestyle
的一个实用包装器,只是寻找一个活动的ExecutionContextScope
。因此,通过显式地启动这样一个作用域(使用BeginExecutionContextScope
),您可以确保存在一个TestDataContext
可以解析的作用域。
我想你在使用其他DI框架时也会遇到同样的问题。这些框架要么也会使用执行上下文,要么允许您将活动解析范围传递给调用者,这两种情况在这种方法中都是不可能的。然而,有些容器会让你认为解析上下文可以工作,而实际上,当没有作用域时,它们返回一个单例实例。使用单例数据上下文当然是一件非常糟糕的事情,你的应用程序会严重崩溃。但它当然只会在生产环境中中断,因为这是并发性错误的问题。