【问题标题】:Downloading a dynamic file下载动态文件
【发布时间】:2013-09-03 19:12:00
【问题描述】:

我正在我的 Web 应用程序中动态创建一个文件。我想将此文件发送给用户,就像许多网站在下载文件时所做的一样。

我首先在Download/Stream file from URL - asp.net 尝试了这种方法。但这不起作用,因为我在一个从 ASPX 网页中删除的层的课程中;我的结果是文件覆盖了自己,交替出现我无法创建正确的请求/响应对象。

然后我尝试了这种方法:

try
{

    WebClient myClient = new WebClient();
    string basefile = Path.GetFileName( file_name );
    myClient.DownloadFile( file_name, basefile );
}
    catch (WebException we)
{
        string message = we.Message;
}

这引发了一个异常:对路径“C:\Program Files (x86)\IIS Express\file-being-sent.ext”的访问被拒绝。

那么,我如何流式传输文件?

ETA 我之前的尝试:

    //Create a WebRequest to get the file
    HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create( url ); //Send request to this URL

    //Create a response for this request
    HttpWebResponse fileResp = (HttpWebResponse)fileReq.GetResponse();

    //if (fileReq.ContentLength > 0)
    //    fileResp.ContentLength = fileReq.ContentLength;

    //Get the Stream returned from the response
    //stream = new Stream();
    writer = new StreamWriter( file_name );
    //stream = writer.BaseStream.Length


    // prepare the response to the client. resp is the client Response
    var resp = HttpContext.Current.Response;

    //Indicate the type of data being sent
    //resp.ContentType = "application/octet-stream";
    resp.ContentType = "application/zip";

    //Name the file 
    resp.AddHeader( "Content-Disposition", "attachment; filename=\"" + Path.GetFileName( file_name ) + "\"" );
    resp.AddHeader( "Content-Length", writer.BaseStream.Length.ToString() );
    // Verify that the client is connected.

    if (resp.IsClientConnected)
    {
        resp.Write( writer );
        resp.Flush();
    }

我还没想好要传递给HttpCreateRequest()的调用。

ETA2:这是我目前使用的。各种 SOF 帖子说这应该通过打开或保存对话框提示用户,但对我来说仍然没有这样做。

StreamReader reader = new StreamReader( file_name );
var resp = HttpContext.Current.Response;

//Indicate the type of data being sent
resp.ContentType = "application/zip";
resp.AppendHeader( "Content-Disposition", "attachment; filename=\"" + Path.GetFileName( file_name ) + "\"" );
resp.AppendHeader( "Content-Length", reader.BaseStream.Length.ToString() );
// Verify that the client is connected.

if (resp.IsClientConnected)
{
    resp.Clear();
    resp.TransmitFile( file_name ); //does not buffer into memory, therefore scales better for large files and heavy usage
    resp.Flush();
}

ETA3:IIS 跟踪日志报告了一个异常,System.Web.HttpException: Server cannot set content type after HTTP headers have been sent. 这对我来说没有意义,因为我在附加标头之前设置了内容类型。

堆栈跟踪是:

[HttpException (0x80004005): Server cannot set content type after HTTP headers have been sent.]
System.Web.HttpResponse.set_ContentType(String value) +9681570
System.Web.HttpResponseInternalWrapper.set_ContentType(String value) +41
System.Web.UI.PageRequestManager.RenderPageCallback(HtmlTextWriter writer, Control pageControl) +139
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +268
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8
System.Web.UI.Page.Render(HtmlTextWriter writer) +29
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +57
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1386

ETA4:我将流移动到 ASPX 页面的代码隐藏文件中,该文件可以直接访问 Response 对象。我仍然遇到同样的异常。我无法解释为什么普遍接受的方法向我抱怨已发送响应,或者为什么我的代码不会提示用户下载文件。

【问题讨论】:

  • @Romoku:我从哪里获得Responsepage 对象?
  • @CodeswithHammer 您需要从 ASPX 或 ASCX 显式传递它。
  • 事实证明,writer = new StreamWriter( file_name ); 会覆盖现有文件。有谁会想过?我已将其更改为 StreamReader - 但它仍然没有流式传输。
  • @Romoku:我现在直接使用Response 对象(参见ETA4)。还是没有运气。

标签: c# asp.net


【解决方案1】:

只需将你所有的内容类型和标题代码移到resp.Clear()之后

using (StreamReader reader = new StreamReader( file_name ))
{
  var resp = HttpContext.Current.Response;
  resp.BufferOutput = true; //this is from the SO article
  //resp.Buffer = True;       //this is from msdn comments

  // Verify that the client is connected.

  if (resp.IsClientConnected)
  {
    resp.Clear();
    resp.ClearHeaders();
    //Indicate the type of data being sent
    resp.ContentType = "application/zip";
    resp.AppendHeader( "Content-Disposition", "attachment; filename=\"" + Path.GetFileName( file_name ) + "\"" );
    resp.AppendHeader( "Content-Length", reader.BaseStream.Length.ToString() );
    resp.TransmitFile( file_name ); //does not buffer into memory, therefore scales better for large files and heavy usage
    resp.End();
  }
}

【讨论】:

  • 应该起作用,Tomb。但它对我没有这样做。 (这一直是主题——在我的情况下,应该有效的方法却没有成功。)
  • 您是否有可能将其包含在 Task 或后台线程中?
  • 我发现 this SO post 可能会有所帮助。我已将代码添加到我的答案中,看看是否有帮助。
  • 我没有为此使用async/await/Task<T>。 (但我试图这样做是为了清理。)而且我很确定自从我第一次发布这个帖子以来,我一直在使用resp.BufferOutput = true;
  • 我真的认为这与您从 aspx 页面中“删除了一层”这一事实有关。有没有什么办法可以用更多的代码来更新你的问题,提供一个例子来说明这个问题?这可能是一个简单的修复,例如将页面上下文传入,甚至将文件传回并从原始 aspx 页面传输。它还可能会指出您正在使用网络服务或其他东西。
【解决方案2】:

在你的 ASPX <%@ Page...%> 指令中设置 ContentType 属性:

<%@ Page ContentType="application/zip" %>

【讨论】:

  • 我试试看。
猜你喜欢
  • 2011-02-18
  • 2018-06-09
  • 2011-12-19
  • 2012-03-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多