使用依赖注入的WebApi等效于HttpContext.Items的方法

5
我正在构建一个ASP.NET WebApi 2.1应用程序,需要一个类似于HttpContext.Items的每个请求缓存。
即使在IIS托管下,由于在服务/存储库层中执行异步工作(使用TPL调用而不是async/await以匹配某些接口),HttpContext似乎也会丢失(HttpContext.Current变为null),因此我不能使用HttpContext。
我正在使用Unity 3.5,并且无法实现适当的每个请求注入。尝试了HttpControllerActivator方法:
public class HttpControllerActivator : IHttpControllerActivator
{
    private readonly IUnityContainer _container;
    private readonly IHttpControllerActivator _activator;

    public HttpControllerActivator(IUnityContainer container, IHttpControllerActivator activator)
    {
        _container = container;
        _activator = activator;
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        IHttpController controller = _activator.Create(request, controllerDescriptor, controllerType);
        _container.RegisterInstance<System.Net.Http.HttpRequestMessage>(request, new HierarchicalLifetimeManager());

        return controller;

    }
}

但是这注册了HttpRequestMessage到根容器上,而不是在_activator.Create内部的BeginScope()调用创建的子容器上。因此,在并发负载下,我会得到混合的请求实例。
有没有什么办法解决这个问题?我已经在线搜索了两天,还没有找到任何真正解决这个问题的方法...
1个回答

2
使用 TPL 调用,而不是 async/await,因为需要匹配某些接口。
我建议您再次查看 async 和 await。可以使用 async 实现您的部分,并使其与其他异步 API 相互操作
话虽如此,如果您想保留 HttpContext.Current(以及文化等),则关键在于 SynchronizationContext。我有一篇MSDN 文章介绍了该类型,您可能会发现它很有帮助。由于您的代码正在使用 TPL,因此您可能希望将请求上下文捕获到一个任务调度程序中:
var requestContext = TaskScheduler.FromCurrentSynchronizationContext();

然后使用它来安排任务的继续执行。
ASP.NET 中异步工作的另一个重要方面是确保运行时知道您的异步工作。您可以在异步工作开始之前调用 AsyncOperationManager.CreateOperation 来注册异步工作,以及调用 AsyncOperation.OperationCompleted 来通知运行时异步工作已完成。或者,您可以捕获 SynchronizationContext.Current 并自己调用 SynchronizationContext.OperationStartedSynchronizationContext.OperationCompleted
再次看一下 asyncawait,看看是否可能使用它们;它们会为您处理所有这些繁琐的细节。

感谢对“同步上下文”进行澄清。实际上,我的应用程序中存在这些异步操作是因为使用了BookSleeve。自从我添加了TaskScheduler.FromCurrentSynchronizationContext()后,我就不再进入继续任务了。此外,我并不是真正喜欢在各个地方都使用那个旧的AsymcOperationManager。所有这一切都让我相信asyncawait是正确的选择,尽管我真的不喜欢必须用Task结果声明我的接口这一事实! - blemasle
是的,在接口中,Task 有点讨厌,非常类似于 IDisposable:你必须猜测任何派生类型是否可能是异步的(或者具有需要处理的资源)。 - Stephen Cleary
由于那个错误,我可能无法在真正需要的函数上使用异步:它们具有类型约束。 我又尝试了一下TaskScheduler,但每当我使用它时,我的调用就会永远挂起(我怀疑asp.net没有“看到”任务已经结束)。有什么想法吗? - blemasle
好的,我找到了我的代码为什么会卡住的原因,具体可以查看这个帖子。现在我进入了一个死角,因为我不得不要么失去HttpContext,要么让我的代码卡住... - blemasle
如果您一直使用async,那么您就不会遇到HttpContext或死锁问题。 - Stephen Cleary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接