0

我目前正在尝试编写一些代码来接受一些 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 它永远不会到达浏览器。

我是在做一些愚蠢的事情还是不可能做到这一点?

我会很感激人们可以在这里提供的任何帮助,因为我在这里浏览了谷歌和其他帖子后完全被卡住了。即使是我的老板,他是一个更有经验的编码员,也不知道如何处理这个问题。

提前致谢,

天然气

4

1 回答 1

1

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

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

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

所以这里是正确的动作签名:

[HttpPost]
public void FtpAsync(Downloads model)
{
    ...
}

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

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

所以你有两种可能性:

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

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

于 2012-07-04T15:50:54.457 回答