代码之家  ›  专栏  ›  技术社区  ›  Odrade

从静态方法调用Response.TransmitFile()

  •  3
  • Odrade  · 技术社区  · 16 年前

    我有许多页面需要支持将数据导出到Excel电子表格。我可以很好地生成Excel文件,但我正在尝试解决如何抽象这种行为,以便可以轻松地从我需要的所有页面重用它。我目前的想法是使用静态实用方法,如下所示:

    public static void SendExcelFile(System.Web.UI.Page callingPage, string downloadFileName, List<List<string>> data, string worksheetTitle)
    {
        string tempFileName = Path.GetTempFileName();
    
        try
        {
            // Generate file using ExcelPackage
            GenerateExcelDoc(tempFileName, data, worksheetTitle);
    
            callingPage.Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
            callingPage.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            callingPage.Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
            callingPage.Response.TransmitFile(tempFileName);
        }
        finally
        {
            //When this is removed, the method works as expected.
            if (File.Exists(tempFileName))
                File.Delete(tempFileName);  
        }
    }
    

    我呼叫的点击处理程序 SendExcelFile 看起来像这样:

    protected void lnkExport_Click(object sender, EventArgs e)
    {
        List<List<string>> dataList = GatherDataForSpreadsheet();
        Utility.SendExcelFile(this, "fileNameForDownload.xlsx", dataList, "MyReports");
    }
    

    这段代码作为调用页面的实例方法工作得很好。但是,作为一种静态方法,它根本不起作用。当我单击调用此功能的按钮时,浏览器会无限期地显示正在加载的动画,但不会提示下载文件。

    我对ASP.NET(以及一般的web编程)非常陌生,所以我确信我在这里遗漏了一些东西。有人能解释一下我看到的行为,并提出一个合理的替代方法吗?

    编辑:如果在最后删除对File.Delete()的调用,则该方法将按预期工作。Response.TransmitFile()是否异步进行传输?

    编辑2:我只需要在删除文件之前调用Response.Flush()。见下面我的答案。 谢谢

    5 回复  |  直到 16 年前
        1
  •  5
  •   Odrade    13 年前

    问题是临时文件在发送数据之前被删除。我只需要调用Response.Flush(),如下所示:

    public static void SendExcelFile(System.Web.UI.Page callingPage, string downloadFileName, List<List<string>> data, string worksheetTitle)
    {
        string tempFileName = Path.GetTempFileName();
    
        try
        {
            // Generate file using ExcelPackage
            GenerateExcelDoc(tempFileName, data, worksheetTitle);
    
            callingPage.Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
            callingPage.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            callingPage.Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
            callingPage.Response.TransmitFile(tempFileName);
            callingPage.Response.Flush();  //This is what I needed
        }
        finally
        {
            if (File.Exists(tempFileName))
                File.Delete(tempFileName);  
        }
    }
    
        2
  •  1
  •   Nick Craver    16 年前

    试试这个,你可以得到 Request Response 马上 HttpContext.Current :

    public static void SendExcelFile(string downloadFileName, List<List<string>> data, string worksheetTitle)
    {
        var context = HttpContext.Current;
        string tempFolder = context.Request.PhysicalApplicationPath + "temp";
        string tempFileName = tempFolder + "tempFileName.xlsx"
    
        if (!Directory.Exists(tempFolder))
            Directory.CreateDirectory(tempFolder);
    
        // Generate file using ExcelPackage
        GenerateExcelDoc(tempFileName, data, worksheetTitle);
    
        context.Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
        context.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        context.Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
        context.Response.TransmitFile(tempFileName);
    
        File.Delete(tempFileName);
    }
    

    另一种选择是为包含此方法的页面创建基类,这可能是一种更简单的路由。您的页面不必从System.Web.UI.Page继承,它们可以从其他内容继承,例如:

    public class BasePage : System.Web.UI.Page
    {
        public void SendExcelFile(string downloadFileName, List<List<string>> data, string worksheetTitle)
        {
            string tempFolder =Request.PhysicalApplicationPath + "temp";
            string tempFileName = tempFolder + "tempFileName.xlsx"
    
            if (!Directory.Exists(tempFolder))
                Directory.CreateDirectory(tempFolder);
    
            // Generate file using ExcelPackage
            GenerateExcelDoc(tempFileName, data, worksheetTitle);
    
           Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
           Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
           Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
           Response.TransmitFile(tempFileName);
    
            File.Delete(tempFileName);
        }
    }
    

    public partial class MyPage : BasePage
    {
      //Stuff!
    }
    
        3
  •  1
  •   Jeff Sternal    16 年前

    我们需要更多的信息-你所做的应该有用。

    我创建了一个精简版,只需将调用页面的副本发送到客户端,即可正常工作:

    public class Utility {
        // This just sends the client a copy of the calling page itself
        public static void SendExcelFile(Page callingPage) {
            string path = callingPage.Request.PhysicalPath;
            callingPage.Response.AddHeader("Content-Disposition", "attachment;filename=test.xls");
            callingPage.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            callingPage.Response.AddHeader("Content-Length", new FileInfo(path).Length.ToString());
            callingPage.Response.TransmitFile(path);
        }
    }
    

    这是我的呼叫页面:

    public partial class main : System.Web.UI.Page {
        protected void SendButton_Click(object sender, EventArgs e) {        
            Utility.SendExcelFile(this);
        }
    }
    

        4
  •  1
  •   Mike Powell    16 年前

    此时,我将使用HTTP调试代理,如 Fiddler 比较代码的工作(页面代码隐藏)和非工作(静态)版本生成的HTTP会话。

    Path.GetTempFileName() 或文件名中的guid,以确保每个用户的文件具有唯一的名称。

        5
  •  0
  •   nbushnell    16 年前

    HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
    HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    HttpContext.Current.Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
    HttpContext.Current.Response.TransmitFile(tempFileName);
    
    推荐文章