繁体   English   中英

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

[英]Calling Response.TransmitFile() from static method

我有很多页面需要支持将数据导出到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()。 请参阅下面的答案。 谢谢!

问题是在发送数据之前删除了临时文件。 我只需要像这样调用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);  
    }
}

试试这个,你可以直接从HttpContext.Current获得RequestResponse

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!
}

我们需要更多信息-您在做什么应该有用。

我创建了一个精简版本,该版本仅将调用页面的副本发送到客户端,并且可以按预期工作:

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

您看到与实施方式有什么不同吗?

在这一点上,我将使用像Fiddler这样的HTTP调试代理来比较由您的代码的工作版本(后台代码)和非工作版本(静态)生成的HTTP会话。

顺便说一句,您应该意识到,如果多个用户同时单击按钮,则编写的代码将无法正常工作-第一个用户的临时文件可能会被第二个用户的文件覆盖,而第二个用户的临时文件可能会被覆盖。文件可能在传输过程中被删除! 考虑使用Path.GetTempFileName()或文件名中的guid以确保每个用户的文件都具有唯一名称。

我会用它代替。 当前的HTTP上下文将在每个页面上可用。

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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM