我使用自定义 JsonMediaTypeFormatter 来扩展请求中的数据。但是当我使用 GetInstance 方法时,格式化程序会抛出异常。我做错了什么?
全局.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);
}
}
这是异常消息:
The registered delegate for type TestDataContext threw an exception. The TestDataContext is registered as 'Web API Request' lifestyle, but the instance is requested outside the context of a Web API Request.
有点困惑的堆栈跟踪:
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
。但是,尽管在 IDependencyScope
的开始和结束之间调用 WriteToStream
,但它并不是在与 Web API 请求的其余部分相同的执行上下文中调用。
这意味着对于 Simple Injector 而言,当时没有请求,因为 Simple Injector 使用 .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);
}
}
WebApiRequestLifestyle
实际上只是 ExecutionContextScopeLifestyle
的实用包装器,只是查找事件的 ExecutionContextScope
。因此,通过显式启动这样的范围(使用 BeginExecutionContextScope
),您可以确保存在一个可以解析 TestDataContext
的范围。
我想你在使用其他 DI 框架时也会遇到同样的问题。这些框架也将使用执行上下文,或者它们允许您将事件解析范围传递给调用者,这两种情况在此方法中都是不可能的。然而,某些容器会让您认为解析上下文会起作用,而实际上,当没有作用域时,它们会返回一个单例实例。使用单例数据上下文当然是一件非常糟糕的事情,您的应用程序将严重崩溃。但它当然只会在生产中中断,因为那是并发错误的薄弱环节。
关于c# - 在自定义 TypeFormatter 中使用 RegisterWebApiRequest 时出现 SimpleInjector.ActivationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23884775/