从Session_Start调用异步方法

Dan*_*lle 4 asp.net-mvc session asynchronous async-await .net-4.5

如何在Global.asax中调用异步方法Session_Start

Global.asax中:

    protected async Task Session_Start(object sender, EventArgs e)
    {            
        Session.Timeout = 10;

        // Do some asynch work
        await repository.SetStatsInfo(System.DateTime.Now);            
    }
Run Code Online (Sandbox Code Playgroud)

异步方法:

    public async Task SetStatsInfo(DateTime time)
    {
        using (ApplicationDBContext db = new ApplicationDBContext())
        {
            // Do stuff (update visitors counter in db) ..

            await db.SaveChangesAsync();

        }
    }
Run Code Online (Sandbox Code Playgroud)

我可以同步运行它(定义void Session_Start等),但它更喜欢异步方式,以便命中数据库不会阻塞.

使用'async Task' Session_Start执行此操作时,代码不会执行,内部session_start的断点不会被命中.

小智 7

根据我的理解,ASP有一个指定的线程,它是唯一可以访问该HttpContext.Current对象的线程,反过来,访问Session(HttpContext.Current.Session)就像在Windows应用程序中的UI线程一样.因此,执行.Wait().Result在Session_Start回调中将为您提供未知结果和/或使进程死锁.

似乎有很多方法来管理Task的执行线程,主要的方法是通过TaskScheduler类https://msdn.microsoft.com/en-us/library/system将您的任务指定为使用某个同步上下文运行. threading.tasks.taskscheduler(v = vs.110).ASPX#同步

但是,由于Task类被设计为实现IAsyncResult,它来自APM(异步编程模型)模式,这使得Task向后兼容旧的APM模式代码(根据我最初构建的ASP的理解).虽然https://blogs.msdn.microsoft.com/mazhou/2011/10/04/the-asynchronous-programming-models/(标准APM),但它需要一些集成工作.

.Net 4.5引入了一个很好的Task wrapper(EventHandlerTaskAsyncHelper)来执行异步动作,利用APM风格HttpApplication构建来支持.它满足访问Session对象的所有要求,并在以下内容中正确执行HttpApplication:

public override void Init()
{
    base.Init();
    //EventHandlerTaskAsyncHelper Wraps the task call in an APM-style BeginEventHandler, EndEventHandler
    var wrapper = new EventHandlerTaskAsyncHelper(AsyncSessionStart);
    this.AddOnAcquireRequestStateAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler);
}

private async Task AsyncSessionStart(Object sender, EventArgs evtArgs)
{       
    //The only caveat is we have to check IsNewSession to see if it was created in this call
    //This doesn't need to be applied for other AddOn*Async wire-ups
    if (!Session.IsNewSession)
        return;

    await doSomethingAsync();
}

//I recall seeing something that for session state to be active, this callback has to be declared, even if empty
protected void Session_Start(object sender, EventArgs e)
{
    //Synchronous session
}
Run Code Online (Sandbox Code Playgroud)

  • 对此的注释:如果没有会话,[`HttpApplication.Session`](https://learn.microsoft.com/en-us/dotnet/api/system.web.httpapplication.session) 属性会引发异常 (例如,在获取捆绑资源时会发生这种情况)。因此,您最好使用“if (HttpContext.Current?.Session?.IsNewSession != true) return;”进行检查 (2认同)

Chr*_*att 3

Global.asax 中的那些方法Session_Start很特殊。你不能随意定义新的。该框架运行其编程运行的框架,并且不提供异步版本。因此,不会运行任何异步版本。

然而,无论如何,异步其实并没有什么意义。Global.asax 方法在应用程序池启动和关闭时调用。因此,在任何时候放弃操作线程都是没有意义的,因为在它完成其工作之前不会发生任何其他事情。

我不完全确定你在做什么,但根据代码中的注释,听起来无论如何这都不是正确的地方。同样,此代码仅运行一次,而不是针对每个请求运行。如果您希望每个请求发生一些事情,请研究诸如操作过滤器之类的东西。

  • 您指的是“Application_Start”吗?每次创建新会话时都会触发“Session_Start”事件,如以下所述:[http://forums.asp.net/t/1230163.aspx?What+s+the+difference+ Between+Application_Start+and+Session_Start +in+Global+aspx+](http://forums.asp.net/t/1230163.aspx?+Application_Start+和+Session_Start+in+Global+aspx+之间的+区别是什么) (3认同)