在Identity Framework的方法中,HttpContext.Current为null [英] HttpContext.Current is null inside Identity Framework's methods

查看:128
本文介绍了在Identity Framework的方法中,HttpContext.Current为null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ASP.NET MVC 5和Identity Framework.当我调用UserManager.UpdateAsync(...)时,ApplicationDbContext()上的事件处理程序将运行SaveChanges.在这里,我将HttpContext.Current用于不同的目的(记录和审核),因此我必须说当前用户.但是,整个方法都在工作线程中运行,这里HttpContext.Current为null.

I am using ASP.NET MVC 5 and Identity Framework. When I call UserManager.UpdateAsync(...) my eventhandlers on ApplicationDbContext() SaveChanges will run. Here I am using HttpContext.Current for different purposes (logging and auditing) so I must get say current user. However the whole method runs in a worker thread, and here HttpContext.Current is null.

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

The biggest problem that the UserManager's "sync" methods are only wrappers around the async version, so the calls are serialized, but the methods (and eventhandlers) still run in a different worker thread.

请注意,此问题与async/await上下文无关.在等待(或调用同步"版本)之后,在控制器中,我已经返回了正确的HttpContext,即使控制器的方法正在其他线程中继续执行.很好.

Please note this issue has nothing to do with the async/await context. In the controller after the await (or calling the 'sync' version) I have back the correct HttpContext, even the controller's method is continuing in an other thread. That's fine.

因此问题出在异步工作程序内部,该工作程序将同时在"sync"和异步版本中运行.我认为我已经了解了这种现象(但是我对假的同步"方法版本不满意,真正的同步方法不会出现此问题.)我只是不知道如何处理/解决它.

So the problem is inside the async worker which will run in both the "sync" and async versions. I think I am understanding the phenomena (but I am not happy with the fake 'sync' method versions, real sync methods would not exhibit this issue.) I just does not know how to deal/workaround it.

[btw:将UserManager的操作实现为简单的纯同步版本,然后通过异步多线程包装器将它们包装起来,会不会更自然?如果我们继续这种异步方式而没有想到我们将很快发明异步分配运算符.它花费了我数十个小时的时间(仅此问题),并且在全球范围内花费了数十亿美元,在许多情况下,我相信回报要比价格低.]

[btw: Would not it be more natural to implement UserManager's operarations as simple pure sync versions, then wrap them by async multithreaded wrappers?. IF we continue this async fashion without thinking we will soon invent the async assignment operator. It costs me dozens of hours (just this issue), and costs worldwide zillion dollars, I am sure in many cases less return than its price.]

奖金:我们谈论的是UserManager,它的影响很小,但是相同的原理和问题可以应用于任何现成的库(对您来说都是黑盒),即作者没有实现同步版本或不关心控制器.线程的上下文. EF呢,不是那么重要...以及DI容器实例化基础架构,例如请求范围"或会话范围".如果解析发生在没有HttpContext.Current的线程中,则它们肯定会表现不佳.最近,我刷新了SendGrid NuGet,并(作为一项重大更改)取消了Deliver()方法,现在仅存在DeliverAsync()...

Bonus: We are talking about UserManager which's impact pretty marginal, but the same principles and issues can apply any out of the box library (black box for you) which authors do not implement sync versions and or do not care about the controller thread's context. What about EF, it is not so marginal... and what about DI containers instantiation infrastructure like "request scope" or "session scope". Surely they misbehave if resolving occurs in a thread with no HttpContext.Current. Recently I refreshed SendGrid NuGet, and (as a breaking change) Deliver() method gone, and now only DeliverAsync() is existing...

我希望有一种安全可靠的方法,如何在此工作程序内访问HttpContext以便进行日志记录和审核.

I would like to have a safe reliable way, how can I access the HttpContext inside this worker for logging and audit purposes.

示例代码,控制器的同步"版本:

Sample code, the controller 'sync' version:

[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.
}

示例代码,控制器异步版本:

Sample code, the controller async version:

[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的事件处理程序:

and the event handler where HttpContext is null:

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

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

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

有什么想法吗?

推荐答案

正如您所说,这是由于线程化而发生的.委托在另一个线程中运行,从而使HttpContext无法访问.

As you said, this occurs because of threading. The delegate runs in a different thread, making the HttpContext inaccessible.

您可以将变量移到委托之外,使其成为闭包.

You can move the variable outside of the delegate, making it a closure.

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

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

这篇关于在Identity Framework的方法中,HttpContext.Current为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆