如何从MVC4中的异步操作重定向到另一个操作

时间:2012-07-04 15:37:22

标签: c# asp.net-mvc asp.net-mvc-3 asynchronous asp.net-mvc-4

我目前正在尝试编写一些代码来接受一些FTP细节,获取文件列表,然后允许用户下载文件。

这一切都很好,除了我必须等待文件完成下载才会做任何事情。我正在使用异步控制器,因为我认为这是为了帮助解决这类问题。

请在下方查看我的代码选择,我遗漏了所有不相关的代码:

  [HttpPost]
    public ActionResult FtpAsync(Downloads model)
    {
        var ftpAddress = model.Url;
        if (!ftpAddress.StartsWith("ftp://"))
            ftpAddress = String.Concat("ftp://", ftpAddress);

        var serverPath = Server.MapPath(ThumbnailSupport.CreateBaseVirtualPathForClient(StandardFileLinks.DropBoxLocation,
                                                                        _website.Client));

        if (!Directory.Exists(serverPath))
            Directory.CreateDirectory(serverPath);

        foreach (string file in model.SelectedFiles)
        {

            var webClient = new WebClient();

            AsyncManager.OutstandingOperations.Increment();

            AsyncManager.Parameters["FilesToDownload"] = model.SelectedFiles;
            webClient.Credentials = new NetworkCredential(model.Username, model.Password);

            webClient.DownloadFileAsync(new Uri(ftpAddress + "/" + file), serverPath + "\\" + file);
            AsyncManager.OutstandingOperations.Decrement();
        }

        return RedirectToAction("Transfer");

    }


    public ActionResult FtpCompleted(Downloads model)
    {
        return RedirectToAction("Complete");
    }

    public ActionResult Transfer()
    {
        return PartialView();
    }

它完全解除了FtpCompleted操作,但问题是这是为了处理潜在GB信息的文件传输。我不希望用户在等待下载文件时坐着观看旋转的光盘。因此,我试图将它们重定向到转移操作的原因,此操作只显示一条消息,告诉他们转移可能需要一段时间,一旦完成,它们将会收到通知。然而,这个动作实际上从未被调用。我在调试中单步执行代码并调用它,但它从不显示消息,并且根据FireBug它永远不会到达浏览器。

我做了些蠢事还是不可能做到这一点?

我很感激人们可以在这里提供任何帮助,因为我在这里浏览谷歌和其他帖子后完全陷入困境。即使我的老板是一位经验更丰富的编码员,也不确定如何处理这个问题。

提前致谢,

达伽兹

1 个答案:

答案 0 :(得分:1)

documentation中所述,异步控制器操作由2个方法组成:

  1. 返回 void 且具有Async后缀和操作名称前缀
  2. 的方法
  3. 返回 ActionResult 并具有Completed后缀和操作名称前缀
  4. 的方法

    第一种方法触发异步操作并立即返回。整个操作完成后,将调用第二种方法。

    所以这是正确的行动签名:

    [HttpPost]
    public void FtpAsync(Downloads model)
    {
        ...
    }
    
    public ActionResult FtpCompleted(Downloads model)
    {
        return Content("Complete");
    }    
    

    现在,如果您不想在整个操作期间冻结浏览器,则必须使用AJAX调用第一个控制器操作。异步控制器不会根据HTTP协议进行任何更改。从客户的角度来看,它绝对是一样的。与标准控制器操作的唯一区别在于,您不会在整个操作期间危害工作线程。您现在依赖的是WebClient使用的操作系统工件的IOCP(IO /完成端口)。我们的想法是,当您启动IO密集型操作时,会创建一个IOCP端口,并且控制器操作会立即将该线程返回到ASP.NET线程池。然后,该操作可能持续数小时,并且一旦完成IOCP信号,就会从线程池中抽取池,并在此线程上调用Completed操作。所以就线程而言,这是非常有效的。但是执行的总时间与使用标准控制器操作完全相同。许多人认为,因为异步控制器被称为异步,所以它们从客户端角度异步运行。这是一种错误的印象。异步操作不会使您的操作奇迹般地运行得更快。从客户端的角度来看,它们仍然完全同步,因为这就是HTTP协议的工作方式。

    所以你有两种可能性:

    • 使用AJAX调用控制器操作以避免阻止浏览器。
    • 使用COMET / PUSH技术,它是通知客户端的服务器。例如,在HTML5中,可以使用WebSockets标准来实现这一目标。在.NET世界中,SignalR是一个很好的框架,它封装了这种PUSH技术。

    如果您想要一个非常有效的解决方案,建议使用第二种方法。