异步在异步控制器mvc 4.0中不起作用

时间:2015-01-30 07:45:50

标签: c# asp.net-mvc asynchronous

我的目标是在targetFramework =“4.5”处跟踪MVC 4.0应用程序。

我必须基本上将文件处理的现有功能从同步转换为异步(以便大文件用户不必等待其他任务)。

我的代码是

[HttpPost]
        public async Task<ActionResult> FileUpload(HttpPostedFileBase fileUpload)       
 {

Coreservice objVDS = new Coreservice ();

   //validate the contents of the file 
model =objVDS. ValidateFileContents(fileUpload);

// if file is valid start processing asynchronously
     await Task.Factory.StartNew(() => { objVDS.ProcessValidFile(model); },                                CancellationToken.None,
                    TaskCreationOptions.DenyChildAttach,
                    TaskScheduler.FromCurrentSynchronizationContext());

return view();


}

基本上我想调用一个异步方法,该方法位于执行数据库操作的服务中(不同的项目)。

我希望异步进程能够访问services方法中的上下文。这就是我使用的原因 TaskScheduler.FromCurrentSynchronizationContext()中的Task.Factory.StartNew()

服务方法如下所示,其中,基于文件类型,第二个服务被调用进行数据操作

public async task ProcessValidFile(fileProcessDataModel model)
{
employeeWorkedDataservice service =new employeeWorkedDataservice()

 await Task.Factory.StartNew(() =>
                                        {
                                            service .ProcessEmployeeDataFile(model.DataSetToProcess, OriginalFileName, this, model.Source);
                                        },
                                        CancellationToken.None,
                                        TaskCreationOptions.DenyChildAttach,
                                 TaskScheduler.FromCurrentSynchronizationContext());    

}

ProcessEmployeeDataFile返回void并且它不是异步方法。 当执行上面的代码时,它不会返回到控制器,直到它完成数据处理。我想我在这里遗漏了一些东西。 请指导我解决。

谢谢, AMOL

2 个答案:

答案 0 :(得分:3)

您似乎误解了await的工作方式。

阅读此https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_WhatHappensUnderstandinganAsyncMethod

设置在任务中运行的某些内容将允许它以异步方式运行,这样您就可以在其运行时执行其他操作。

如果您需要继续使用结果,请使用await关键字。

通过立即await创建任务,您可以立即阻止任务结算;使其有效同步。

如果您很乐意在不等待处理完成的情况下回到您的观点,我认为您根本不需要await,因为您根本不想等待操作的结果。

public task ProcessValidFile(fileProcessDataModel model)
{
    employeeWorkedDataservice service =new employeeWorkedDataservice()

    return Task.Factory.StartNew(() =>
    {
        service.ProcessEmployeeDataFile(model.DataSetToProcess, OriginalFileName, this, model.Source);
    },
    CancellationToken.None,
    TaskCreationOptions.DenyChildAttach,
    TaskScheduler.FromCurrentSynchronizationContext());    
}

[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase fileUpload)       
{

    Coreservice objVDS = new Coreservice ();

   //validate the contents of the file 
   model =objVDS. ValidateFileContents(fileUpload);

   // if file is valid start processing asynchronously
   // This returns a task, but if we're not interested in waiting
   // for its results, we can ignore it.
   objVDS.ProcessValidFile(model);

   return view();
}

关于你的意见:

我会认真考虑将您的控制器传递给您的服务,或者让您的服务依赖于会话和上下文,因为您将业务逻辑与API控制器紧密耦合。

在您进入服务器时从控制器获取所需的位并将其传递给您的服务。

答案 1 :(得分:3)

  

我必须基本上将文件处理的现有功能从同步转换为异步(以便大文件用户不必等待其他任务)。

那不是async所做的;正如我在博客中描述的async does not change the HTTP protocol

你想要的是ASP.NET上某种形式的“火与忘”。我有另一篇博文covers a few solutions。请注意,使用Task.Factory.StartNew是所有这些解决方案中最危险的。

最好的(读取:最可靠)解决方案是使用适当的分布式架构:您的ASP.NET应用程序应创建要完成的工作的描述并将其放在可靠的队列中(例如,MSMQ);然后有一个处理队列的独立后端(例如,Win32服务)。这很复杂,但比试图强制ASP.NET执行从未打算做的事情要容易得多。