2012-01-04 56 views
0

我有一個系統,用戶可以從MVC3應用程序中上傳有時大型文件(100-200 MB)。我希望在文件上傳時不要阻止用戶界面,經過一番研究後,它看起來像新的AsyncController可能會讓我做我想做的事情。問題是 - 我看到的每個例子都不是在做同樣的事情,所以我似乎錯過了一件至關重要的事情。多把玩和擺弄之後,這是我當前的代碼:是一個異步控制器apropos在這裏?

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視圖?爲什麼會這樣做,如果它返回無效?我只是希望它在後臺默默執行,插入一條消息並停止。

那麼這是正確的做法嗎?我這樣做的全部理由是網絡速度很快,上傳一個文件需要30分鐘,而在當前版本中,它會阻止整個應用程序,直到它完成。我寧願不使用類似彈出窗口的東西,如果我可以避免它,因爲這會涉及彈出窗口阻止腳本等一系列支持問題。

無論如何 - 我已經沒有想法。建議?幫幫我?替代方法我可能會考慮?

在此先感謝。

+0

你是否考慮uploadify? – 2012-01-04 19:55:17

回答

2

你在這裏做的一切都不對。假設你的動作名稱是Create

  1. CreateAsync將捕獲請求,應該是一個無效方法,並且不返回任何內容。如果您有屬性,則應將其應用於此方法。
  2. CreateCompleted是您應該將其視爲標準控制器操作方法的方法,您應該在此方法中返回您的ActionResult

下面是一個簡單的例子給你:

[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"); 
} 

也請記住,這種方法仍然會阻塞,直到操作完成。這不是一個「隨時隨地」的異步操作。

欲瞭解更多信息,看看:

Using an Asynchronous Controller in ASP.NET MVC

編輯

你想要的這裏是像下面的代碼。忘記所有的東西AsyncController,這是你創建動作後方法:

[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秒後創建。

但(一個大的),在這裏,沒有任何異常處理,邏輯如何通知用戶等

如果我是你,我想看看不同的方法在這裏,或使用戶遭受並等待。

+0

好吧,但阻塞正是我想要避免的那種事情。我希望他們選擇要上傳的文件,讓它開始上傳並轉到顯示「您的文件正在上傳的視圖」,我們會在完成時通知您。 – MonkRocker 2012-01-04 19:51:17

+0

@MonkRocker問題是完全正確的。你想怎麼通知最終用戶?你不能像一個標準的桌面應用程序那樣思考一個Web應用程序 – tugberk 2012-01-04 19:52:56

+0

我的CreateCompleted方法是通知他們的。我已經建立了一個消息系統。我只希望他們能夠回到用戶界面並像普通一樣使用應用程序,然後當文件上傳時,後臺進程會在消息傳遞系統中插入一條消息,他們將在下一頁加載時看到指示符應用程序的任何地方。 – MonkRocker 2012-01-04 20:12:00