ASP.NET MVC2可以通过AsyncController访问HttpContext.Current吗?

时间:2011-02-19 23:34:18

标签: c# jquery asp.net-mvc-2 asynccontroller

我正在尝试将此方法ExportTo3rdParty()转换为使用AsyncController:

public JsonResult SaveSalesInvoice(SalesInvoice invoice)
{
    SaveInvoiceToDatabase(invoice); // this is very quick 
    ExportTo3rdParty(invoice); // this is very slow and should be async
}

但是ExportTo3rdParty()方法在多个地方使用HttpContext.Current(太多不能改变 - 原始编码器没有使用足够的依赖注入)。例如,它调用GetDefaultCurrency()。当通过AsyncController调用ExportTo3rdParty()时,这仍然有效吗?

public Currency GetDefaultCurrency()
{
    Currency currency;
    string key = string.Format("DefaultCurrency_{0}", 
                                HttpContext.Current.User.Identity.Name);
    currency = HttpRuntime.Cache.Get(key) as Currency;
    if (currency == null)
    {
        currency = LookupDefaultCurrency();
        HttpRuntime.Cache[key] = currency;
    }
} 

我知道如果我使用Thread.Start,我无法访问HttpContext.Current。但是AsyncController呢?

1 个答案:

答案 0 :(得分:5)

那么让我问你为什么要使用Async控制器?

你认为它会更快吗?只是因为它慢的东西并不意味着你需要让它变得异步。实际上,由于线程管理/上下文切换开销,您很可能会发现在运行异步时该方法较慢。

我从你所展示的两种方法中可以理解的很少。我猜测ExportTo3Party基本上可以“带外”完成。这是一个外部过程。所以你应该做的是使用MSMQ对作业进行排队(这会立即返回),所以它是非阻塞的。并有一些其他进程/应用程序处理排队的作业。这个其他进程可以是一个在服务器上保持运行的常规控制台应用程序(使用Task Sheduler),它只是在作业到达队列后立即处理。

甚至更简单(如果您没有使用过MSMQ),只需执行外部应用程序(再次使用控制台应用程序)而不是等待应用程序退出。因此,您可以使用System.Diagnostics.Process启动该进程,而不是WaitForExit。

这两种选择都是实现我认为ExportTo3rdParty正在做的事情的正确/更好的方式。看到你没有等待这种方法的反应,就把它归还。

如果我还没说服你,那么:

来自MSDN文档

  

如果异步操作方法调用   一种公开方法的服务   使用BeginMethod / EndMethod   模式,回调方法(即,   作为传递的方法   异步回调参数   Begin方法)可以在a上执行   不受控制的线程   的ASP.NET。在这种情况下,   HttpContext.Current将为null,并且   应用程序可能会遇到竞争   访问成员时的条件   AsyncManager类如   参数。确保你拥有   访问HttpContext.Current   实例并避免比赛   条件,你可以恢复   HttpContext.Current通过调用Sync()   来自回调方法。

     

如果回调完成   同步,回调将是   在一个线程下执行   控制ASP.NET和操作   将序列化,所以没有   并发问题。调用Sync()   来自已经在的线程   ASP.NET的控件未定义   行为。

     

ActionCompleted方法将永远   在一个下面的线程上调用   ASP.NET的控件。因此,做   不要从该方法调用fSync()。

     

您传递给的回调   可以使用a调用Begin方法   受到控制的线程   ASP.NET。因此,您必须检查   调用Sync()之前的这种情况。   如果操作完成   同步(即,如果   CompletedSynchronously是真的),   回调正在原始上执行   线程,你不必打电话   同步()。如果操作完成   异步(即,   CompletedSynchronously为false),.   回调正在线程池上执行   或I / O完成端口线程和你   必须调用Sync()。

http://msdn.microsoft.com/en-us/library/ee728598.aspx