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

Async does not work in asynchronous controller mvc 4.0

我有一个目标为 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();


}

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

我希望异步进程能够访问服务方法中的上下文。这就是我使用的原因 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 returns void 及其非异步方法。 当执行上面的代码时,它不会 return 到控制器,直到它完成数据处理。我想我在这里遗漏了一些东西。 请指导我解决问题。

谢谢, 阿莫尔

看来您误解了 await 的工作原理。

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

在任务中设置一些 运行ning 将允许它 运行 异步,所以你可以在它 运行ning 时做其他事情。

当你需要结果继续时,你使用await关键字。

通过创建任务并立即 awaiting 它,您将立即阻塞直到任务解决;使其有效同步。

如果您愿意 return 无需等待处理完成即可查看您的视图,我认为您根本不需要 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控制器。

当你在控制器中时,从控制器中获取你需要的位,并将它们传递给你的服务。

I have to basically convert the existing functionality of file processing from synchronous to asynchronous (so that for large file user don't have to wait for other task).

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

您想要的是 ASP.NET 上的某种形式的 "fire and forget"。我还有另一个博客 post covers a few solutions。请注意,使用 Task.Factory.StartNew 是所有这些解决方案中最危险的。

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