c# - 如何使 HttpContext 在同步调用的任务中可用?

标签 c# asp.net-mvc-4 asynchronous async-await

在我的 ASP.NET MVC 应用程序中,我需要实现/覆盖一些内部实体,例如 IModelBinder.BindModel() , IActionFilter.OnActionExecuting()等。这些方法正在调用异步方法,但显然我不能将它们变成 async Task<>能够使用 await关键字。

所以我写了下面的“适配器”:

public static T GetResult<T>(Func<Task<T>> func)
{
    var httpContext = HttpContext.Current;

    var proxyTask = Task.Run(() =>
    {
        HttpContext.Current = httpContext;
        return func();
    });

    return proxyTask.Result;
}

这让我调用我的异步 GetData()以同步方式:

public static async Task<Data> GetData()
{
    if (isCached)
        return GetCachedData();

    var data = await GetOriginalData();
    SetCachedData(data);
    return data;
}

...

var data = GetResult(() => GetData());

好的,它有效,所以我会结束它,但是如您所见,大多数时候,GetData()同步运行,因此无条件生成新线程在性能方面并不好。这让我很烦恼,所以我最终得到了一个不同的解决方案:

public static T GetResult<T>(Func<Task<T>> func)
{
    var syncContext = SynchronizationContext.Current;
    SynchronizationContext.SetSynchronizationContext(null);

    var task = func();

    SynchronizationContext.SetSynchronizationContext(syncContext);

    return task.Result;
}

它也有效,但问题是自 SynchronizationContext不再流入,没有HttpContext在被调用的方法中可用。

我可能可以通过输入 HttpContext.Current 来解决这个问题进入逻辑 CallContext但我仍然想知道是否有更好的方法来解决这个问题?像定制 SynchronizationContext.Current.CreateCopy() .

最佳答案

spawning a new thread unconditionally

其实就是简单的从线程池中借用一个线程。几乎没有开始一个新线程那么糟糕,但仍然不是最好的性能。

It also works, however the issue is that since SynchronizationContext is no longer flowing in, there is no HttpContext available in the called method.

你确定吗?我希望 HttpContext.Current 设置在 GetData 的开头,以便两种方式调用它。我还希望 HttpContext.Currentawait 之后为 null两种方式调用它。如果在您的测试中 await 之后它不是 null,可能是因为延续恰好在同一个线程上结束。

这是尝试在请求上下文 (SynchronizationContext) 之外使用 HttpContext.Current 的主要问题之一。当您将它放在一个裸线程 (Task.Run) 上时,它会一直呆在那里,直到该线程进入另一个请求上下文。

I could probably work that around by putting HttpContext.Current into logical CallContext

我建议在原始请求上下文中从 Current 中提取您需要的任何数据,然后将该数据显式传递给需要它的方法。

关于原始问题(避免同步情况下的额外线程),我建议只添加一个同步 TryGetData 方法。

关于c# - 如何使 HttpContext 在同步调用的任务中可用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41331644/

相关文章:

c# - 在哪里可以找到 C#/.NET NFS 实现?

c# - 三角形数的约数 (Euler 12)

c# - 覆盖 BMP 文件,无法删除,因为它已被另一个进程使用 - Dispose,使用无效

c# - 如何在使用 MVC 返回函数后调用 javascript?

c# - 值不能为 null 或为空。\r\n参数名称 : name

c# - 找不到 Xamarin ExportRenderer

asp.net - 尝试使用 MVC 4 自定义错误页面找出奇怪的行为。有时我的自定义错误页面会在 404 页面上被绕过

django - 使用 Node.js 将流式 Web api 与 django 结合使用

delphi - 在主线程上下文中执行代码 (Lazarus)

javascript - 使用异步中断 Node 脚本