下载生成的文件后重定向/显示视图

时间:2012-10-25 09:36:59

标签: asp.net-mvc

我有一个控制器动作,可以下载动态生成的文件:

    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不会重新发布表单)

3 个答案:

答案 0 :(得分:10)

正如Ross所说,您只能向HTTP请求返回一个响应。 在这种情况下我做的是:

  1. 将请求发送到服务器
  2. 服务器生成文件并将其存储在某些服务器端数据结构(Cache,Usersession,TempData)中
  3. 服务器返回RedirectToAction()(POST,REDIRECT,GET模式)
  4. 重定向的操作返回带有一些javascript的视图
  5. 通过将window.location.href属性设置为将文件发送回浏览器的特殊下载操作来触发预生成文件的下载

答案 1 :(得分:8)

每个HTTP请求只能有一个响应 - 你试图偷偷进入两个(文件和一个页面)。

通常,当您发送“Content-Disposition:attachment”HTTP标头时,浏览器将保留在当前页面上并弹出文件保存对话框(或自动将文件保存在您的下载中)。

如果您想阻止重新提交表单,则必须更改策略。我建议使用一些javascript来禁用表单的提交按钮并在div叠加层中显示“已完成”消息?

答案 2 :(得分: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")';
}