2016-08-15 35 views
3

如何在Global.asax中从Session_Start调用async方法?从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);    
    } 

异步方法:

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

      await db.SaveChangesAsync(); 

     } 
    } 

我可以同步运行它(定义void Session_Start等),这是工作,但倾向于异步方式,使击球数据库没有阻塞。

以'异步任务'为Session_Start这样运行,代码没有执行, session_start内部的断点没有命中。

+1

Chris说得很对。没有理由这是异步的,因为它根本没有意义。 http://stackoverflow.com/a/38956850/2410379 –

+0

@DavidPine但是,当我们需要使用仅作为异步任务调用的API时,我们应该怎么做? Stephen Clearly已经殴打我们,因为存在死锁的风险,我们决不能调用'GetAwaiter()'或'.Result',所以ASP怎么能。NET应用程序的'Global''Application_Start'方法安全地调用一个异步方法? – Dai

回答

3

Global.asax中的Session_Start这些方法是特殊的。你不能随便定义新的。框架运行它编程运行的框架,并且不提供异步版本。因此,不会运行异步版本。

然而,反正是异步并不合乎情理。在启动和关闭App Pool时调用Global.asax方法。因此,在任何时候放弃操作线程都是没有意义的,因为无论如何,直到完成其工作才能发生任何事情。

我不完全确定你在做什么,但根据你的代码中的评论,它听起来并不像这是正确的做反正的地方。再次,这个代码只运行一次,而不是每个请求。如果您希望每个请求都发生,请查看某个动作过滤器。

+0

正如您所指出的,其目的是在每次新会话开始时更新网站访问者的数量(运行同步,正如我现在所了解的)。 但是,为什么Session_Start不是一个合适的地方呢? – Danielle

+0

因为Global.asax仅在App Pool启动或关闭时运行。同时,任何数量的不同用户都会发生任意数量的请求。如果您要为Session_Start添加某种访问者跟踪逻辑,则只会在App Pool启动时发生一次,并且应用程序池可能会在几小时,几天甚至几周内不会重新启动,具体取决于它如何配置以及状态的服务器。显然,这不会给你非常相关的信息。 –

+0

您是否指'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?What+s+the+difference+between+Application_Start+and+Session_Start+in+Global+aspx+) – Danielle

4

据我了解,ASP都有指定的线程是具有访问HttpContext.Current对象的唯一线索,反过来,访问会话 (HttpContext.Current.Session)很像Windows应用程序的UI线程。因此,在Session_Start回调中执行.Wait().Result会给您未知的结果和/或死锁进程。

似乎有多种方式来管理执行的任务的线程,主要一个是指定你的任务是与通过的TaskScheduler类有一定的同步上下文中运行https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler(v=vs.110).aspx#Sync

然而,由于任务类被设计成实现IAsyncResult,它来自APM(异步编程模型)模式,这使任务向后兼容较旧的APM模式代码(从我了解ASP最初建立的)。它需要一点整合工作,虽然https://blogs.msdn.microsoft.com/mazhou/2011/10/04/the-asynchronous-programming-models/(标准APM)。

.net 4.5引入了一个很好的任务包装器(EventHandlerTaskAsyncHelper)来执行异步操作,利用APM样式HttpApplication构建支持。它满足访问会话对象的所有要求,并且在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 
} 
+1

FYI:The具有ReadOnly会话的页面需要空的Session_OnStart方法,因为SessionStateModule会检查Session_OnStart同步处理程序是否已定义为强制保存会话状态,即使在只读会话中也是如此:http://referencesource.microsoft.com/#System.Web/State/ SessionStateModule.cs,1292 –