这是一个异步控制器apropos?

时间:2012-01-04 19:18:56

标签: asp.net-mvc asp.net-mvc-3 asynchronous

我有一个系统,用户可以从MVC3应用程序中上传有时大的(100-200 MB)文件。我想在文件上传时不阻止UI,经过一些研究,看起来新的AsyncController可能让我做我正在尝试做的事情。问题是 - 我所看到的每一个例子并没有真正做同样的事情,所以我似乎错过了一个关键的部分。经过多次充实和摆弄之后,这是我目前的代码:

public void CreateAsync(int CompanyId, FormCollection fc)
    {
        UserProfile up = new UserRepository().GetUserProfile(User.Identity.Name);
        int companyId = CompanyId;
        // make sure we got a file..
        if (Request.Files.Count < 1)
        {
            RedirectToAction("Create");
        }

        HttpPostedFileBase hpf = Request.Files[0] as HttpPostedFileBase;
        if (hpf.ContentLength > 0)
        {
            AsyncManager.OutstandingOperations.Increment();

            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += (o, e) =>
                {
                    string fileName = hpf.FileName;
                    AsyncManager.Parameters["recipientId"] = up.id;
                    AsyncManager.Parameters["fileName"] = fileName;
                };
            worker.RunWorkerCompleted += (o, e) => { AsyncManager.OutstandingOperations.Decrement(); };
            worker.RunWorkerAsync();

        }

        RedirectToAction("Uploading");
    }

public void CreateCompleted(int recipientId, string fileName)
    {
        SystemMessage msg = new SystemMessage();
        msg.IsRead = false;
        msg.Message = "Your file " + fileName + " has finished uploading.";
        msg.MessageTypeId = 1;
        msg.RecipientId = recipientId;
        msg.SendDate = DateTime.Now;
        SystemMessageRepository.AddMessage(msg);
    }

    public ActionResult Uploading()
    {
        return View();
    }

现在这里的想法是让用户提交文件,调用后台进程,它会做很多事情(为了测试目的,现在只是拉动文件名),同时将它们指向上传视图,它只是说“你的文件正在上传......继续,我们会在它准备好时通知你”。 CreateCompleted方法通过将消息插入用户的消息队列来处理该通知。

所以问题是,我从来没有得到上传视图。相反,我得到一个空白的创建视图。我无法弄清楚为什么。是否因为CreateCompleted方法被调用而显示Create视图?如果它返回无效,为什么会这样做呢?我只是希望它在后台静默执行,插入一条消息并停止。

这是采取ALL的正确方法吗?我这样做的全部原因是有一些网络速度,上传文件可能需要30分钟,而在当前版本中,它会阻止整个应用程序直到完成。如果我可以避免它,我宁愿不使用类似弹出窗口的东西,因为它会遇到弹出阻塞脚本等一堆支持问题。

无论如何 - 我没有想法。建议?救命?我可能考虑的替代方法?

提前致谢。

1 个答案:

答案 0 :(得分:2)

你在这里做错了。假设您的操作名称为Create

  1. CreateAsync将捕获请求,并且应该是一个void方法并且不返回任何内容。如果您有属性,则应将它们应用于此方法。
  2. CreateCompleted是您应该将其视为标准控制器操作方法的方法,您应该在此方法中返回ActionResult
  3. 以下是一个简单的示例:

    [HttpPost]
    public void CreateAsync(int id) { 
    
        AsyncManager.OutstandingOperations.Increment();
    
        var task = Task<double>.Factory.StartNew(() => {
    
            double foo = 0;
    
            for(var i = 0;i < 1000; i++) { 
                foo += Math.Sqrt(i);
            }
    
            return foo;
    
        }).ContinueWith(t => {
            if (!t.IsFaulted) {
    
                AsyncManager.Parameters["headers1"] = t.Result;
            }
            else if (t.IsFaulted && t.Exception != null) {
    
                AsyncManager.Parameters["error"] = t.Exception;
            }
    
            AsyncManager.OutstandingOperations.Decrement();
        });
    
    }
    
    public ActionResult CreateCompleted(double headers1, Exception error) { 
    
        if(error != null)
            throw error;
    
        //Do what you need to do here
    
        return RedirectToAction("Index");
    }
    

    另请注意,此方法仍将阻止操作完成。这不是一场火灾,而是忘记&#34;键入异步操作。

    有关详细信息,请查看:

    Using an Asynchronous Controller in ASP.NET MVC

    修改

    您想要的是以下代码。忘记所有AsyncController的东西,这是你的创建动作post方法:

        [HttpPost]
        public ActionResult About() {
    
            Task.Factory.StartNew(() => {
    
                System.Threading.Thread.Sleep(10000);
    
                if (!System.IO.Directory.Exists(Server.MapPath("~/FooBar")))
                    System.IO.Directory.CreateDirectory(Server.MapPath("~/FooBar"));
    
                System.IO.File.Create(Server.MapPath("~/FooBar/foo.txt"));
    
            });
    
            return RedirectToAction("Index");
        }
    

    请注意,我在那里等了10秒才能让它真实。发帖后,您会看到它会立即返回而无需等待。然后,打开你的应用程序的根文件夹并观看。您会注意到10秒后将创建一个文件夹和文件。

    但是(一个大的),这里没有异常处理,逻辑如何通知用户等。

    如果我是你,我会在这里看一个不同的方法,或者让用户忍受等待。