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.

SimpleInjector.在自定义TypeFormatter中使用RegisterWebApiRequest时出现A

经过一些调试后,我发现Web API处理TypeFormatter的方式有些奇怪。它在创建请求的IDependencyScope之后,但在处置该作用域之前调用WriteToStream。但是,尽管WriteToStreamIDependencyScope的开始和结束之间被调用,但它不是在与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框架时也会遇到同样的问题。这些框架要么也会使用执行上下文,要么允许您将活动解析范围传递给调用者,这两种情况在这种方法中都是不可能的。然而,有些容器会让你认为解析上下文可以工作,而实际上,当没有作用域时,它们返回一个单例实例。使用单例数据上下文当然是一件非常糟糕的事情,你的应用程序会严重崩溃。但它当然只会在生产环境中中断,因为这是并发性错误的问题。

相关文章:
  • 没有找到相关文章