2012-10-25 25 views
11

我有一個下載一個動態生成文件的控制器操作:重定向/顯示視圖dowloaded

public ActionResult DownloadFile() 
    { 
     var obj = new MyClass { MyString = "Hello", MyBool = true }; 
     var ser = new XmlSerializer(typeof(MyClass)); 
     var stream = new MemoryStream(); 
     ser.Serialize(stream, obj); 
     stream.Position = 0; 

     Response.Clear(); 
     Response.AddHeader("Content-Disposition", "attachment; filename=myfile.xml"); 
     Response.ContentType = "application/xml"; 

     // Write all my data 
     stream.WriteTo(Response.OutputStream); 
     Response.End(); 

     return Content("Downloaded"); 
    } 

僅供參考:

public class MyClass 
    { 
     public string MyString { get; set; } 
     public int MyInt { get; set; } 
    } 

這是工作,和文件(myfile.xml)被下載。
然而,消息「下載」不發送給瀏覽器。

同樣,如果我更換return Content("Downloaded");
return Redirect("www.something.com");
然後在瀏覽器的文件下載之前重定向。

帶有一點前導碼,用戶的旅程:

  • 用戶填寫表單上
  • 表單提交
  • 產生
  • XML以前的觀點,並下載
  • 用戶是重定向/「已下載」視圖顯示爲(因此按F5將不會重新發布表單)

回答

7

每個HTTP請求只能有一個響應 - 你試圖潛入兩個(文件和一個頁面)。

通常,當你發送一個「內容處置:附件」 HTTP頭,瀏覽器將停留在當前頁面上彈出一個文件保存對話框(或自動保存在您的下載文件)。

你不得不改變你的策略,如果你要防止重新提交表單。我建議使用一些JavaScript來禁用表單的提交按鈕並在div覆蓋圖中顯示「已完成」消息?

9

正如羅斯所說,你只能返回一個響應HTTP請求。 我在這種情況下,要做的是:

  1. 將請求發送給服務器
  2. 服務器生成的文件,並將其存儲在一些服務器端數據結構(高速緩存,Usersession,TempData的)
  3. 服務器返回RedirectToAction()(POST,重定向,GET模式)
  4. 重定向操作返回與一些JavaScript這
  5. 通過window.location.href屬性設置爲專門的下載行爲,其發送觸發預生成文件的下載,查看s文件返回給瀏覽器
5

這裏是我重定向文件下載後。 主要的邏輯是等待重定向直到文件被下載。 爲此,服務器側的響應被計算並使用重定向服務器端響應時間+一些偏移被延遲。

服務器端控制器代碼:

[HttpPost] 
public ActionResult GetTemplate() 
    { 
     return Json(new {Url = Url.Action("ReturnTemplate") }); 
    } 

[HttpGet] 
public ActionResult ReturnTemplate() 
    { 
     FileResult fileResult = // your file path ; 
     return fileResult; 
    } 

客戶端代碼:

<div id="btnGen" align="right"><button class="main-button"  id="generateTemplate" type="Submit"></div> 

的Javascript:

$("#generateTemplate").click(function() { 
    var startTime = (new Date()).getTime(), endTime; 

     $.ajax({ 
      url: '@Url.Action("GetTemplate", "Controller")', 
      type: 'POST', 
      traditional: true, 
      dataType: "json", 
      contentType: "application/json", 
      cache: false, 
      data: JSON.stringify(), 
      success: function (result) { 
       endTime = (new Date()).getTime(); 
       var serverResponseTime = endTime - startTime + 500; 
       setInterval(function() { Back() }, serverResponseTime); 
       window.location = result.Url; 
      } 
     }); 
}); 

function Back() { 
    window.location = '@Url.Action("Index","Controller")'; 
}