c# - HttpContext.Current 在 Identity Framework 的方法中为 null

标签 c# asp.net-mvc async-await asp.net-identity asp.net-identity-2

我正在使用 ASP.NET MVC 5 和身份框架。当我调用 UserManager.UpdateAsync(...) 时,我在 ApplicationDbContext() SaveChanges 上的事件处理程序将运行。在这里,我将 HttpContext.Current 用于不同的目的(日志记录和审计),所以我必须说出当前用户。但是整个方法在工作线程中运行,这里 HttpContext.Current 为空。

最大的问题是 UserManager 的“同步”方法只是异步版本的包装器,因此调用是序列化的,但方法(和事件处理程序)仍然在不同的工作线程中运行。

请注意此问题与异步/等待上下文无关。在等待(或调用“同步”版本)之后的 Controller 中,我返回了正确的 HttpContext,即使 Controller 的方法也在另一个线程中继续。没关系。

所以问题出在将在“同步”和异步版本中运行的异步 worker 内部。我想我正在理解这种现象(但我对假的“同步”方法版本不满意,真正的同步方法不会出现这个问题。)我只是不知道如何处理/解决它。

[顺便说一句:将 UserManager 的操作实现为简单的纯同步版本,然后用异步多线程包装器包装它们不是更自然吗?。如果我们不假思索地继续这种异步方式,我们很快就会发明异步赋值运算符。它花费了我几十个小时(仅这一期),并且在全局范围内花费了数以亿计的美元,我确信在很多情况下返回低于它的价格。]

奖励:我们谈论的是 UserManager,它的影响很小,但是相同的原则和问题可以适用于任何开箱即用的库(对你来说是黑盒子),作者没有实现同步版本或者不关心 Controller 线程的上下文。 EF 怎么样,它不是那么边缘……还有像“请求范围”或“ session 范围”这样的 DI 容器实例化基础设施。如果解析发生在没有 HttpContext.Current 的线程中,它们肯定会行为不端。最近我刷新了 SendGrid NuGet,并且(作为重大更改)Deliver() 方法消失了,现在只有 DeliverAsync() 存在...

我想要一个安全可靠的方法,我如何才能访问这个 worker 中的 HttpContext 以进行日志记录和审计。

示例代码, Controller “同步”版本:

[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Edit(ApplicationUser user)
{
    // validation etc
    // Update() seems to be only a poor wrapper around the async version, still uses a worker thread.
    var result = UserManager.Update(user);
    // Note: HttpContext is correct here so it is not an async/await problem

    // error handling, creating ActionResult etc.
}

示例代码, Controller 异步版本:

[AcceptVerbs(HttpVerbs.Post)]
public virtual async Task<ActionResult> Edit(ApplicationUser user)
{
    // validation etc
    var result = await UserManager.UpdateAsync(user);
    // Note: HttpContext is correct here so it is not an async/await problem

    // error handling, creating ActionResult etc.
}

以及 HttpContext 为 null 的事件处理程序:

public ApplicationDbContext() : base("DefaultConnection", false)
{
    InitializeAudit();
}

private void InitializeAudit()
{
    var octx = ((IObjectContextAdapter) this).ObjectContext;

    octx.SavingChanges +=
        (sender, args) =>
        {
            // HttpContext.Current is null here
        };
}

有什么想法吗?

最佳答案

正如您所说,这是由于线程而发生的。委托(delegate)在不同的线程中运行,使 HttpContext 不可访问。

您可以将变量移出委托(delegate),使其成为闭包。

private void InitializeAudit()
{
    var octx = ((IObjectContextAdapter) this).ObjectContext;
    HttpContext context = HttpContext.Current;

    octx.SavingChanges +=
        (sender, args) =>
        {
            // context is not null
        };
}

关于c# - HttpContext.Current 在 Identity Framework 的方法中为 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31419033/

相关文章:

asp.net-mvc - 使用 ASP.NET MVC 操作过滤器呈现不同的菜单

asp.net-mvc - 我可以使用Visual Studio的快速版本制作ASP.NET MVC2应用程序吗?

asynchronous - 如何在 Flutter 的异步任务中启动异步任务?

c# - 这是 async void 的正确用法吗? Xamarin

c# - 为什么 C# 编译器重载解析算法将具有相同签名的静态成员和实例成员视为相等?

c# - 合并两个 IGrouping 集

c# - 有多少线穿过障碍物

c# - WPF如何同时播放两个声音文件?

asp.net - Signalr - 将用户名与 ConnectionId 关联

python - 如何调试异步python代码?