2011-04-08 35 views
57

Necesito transmitir un archivo que dará como resultado guardarlo en el navegador. El problema es que el directorio donde se encuentra el archivo está prácticamente mapeado, por lo que no puedo usar Server.MapPath para determinar su ubicación real. El directorio no está en la misma ubicación (o incluso servidor físico en los cuadros activos) que el sitio web.Descargar/Transmitir archivo desde la URL - asp.net

Me gustaría algo como lo siguiente, pero eso me permitirá pasar una URL web, y no una ruta de archivo del servidor.

Puede que tenga que terminar construyendo mi ruta de archivo desde una ruta base de configuración, y luego anexar en el resto de la ruta, pero espero poder hacerlo de esta manera.

var filePath = Server.MapPath(DOCUMENT_PATH); 

if (!File.Exists(filePath)) 
    return; 

var fileInfo = new System.IO.FileInfo(filePath); 
Response.ContentType = "application/octet-stream"; 
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", filePath)); 
Response.AddHeader("Content-Length", fileInfo.Length.ToString()); 
Response.WriteFile(filePath); 
Response.End(); 
+0

Nos puedes contar un poco de lo que entendemos por "prácticamente asignada"? ¿Una carpeta virtual de IIS accesible por URL? – EventHorizon

+0

Está utilizando una ruta VPP, que es un concepto utilizado por EpiServer CMS Configuramos el nombre de la ruta virtual (es decir, "/ documentos /") y luego especificamos qué ruta física también debe mapear (ej. "// nombre de servidor/documentos") El sistema luego crea esta referencia al directorio en tiempo de ejecución. Puede navegar a los archivos a través de la URL web sin problema – mp3duck

+0

El nombre del archivo es de hecho accessibile vía URL. Necesito usar esta URL para transmitir el archivo, y no la ruta del servidor, ya que no puedo desmarcar esto de la URL (usando MapPath) – mp3duck

Respuesta

84

usted podría utilizar HttpWebRequest para obtener el archivo y transmitirlo al cliente. Esto le permite obtener el archivo con una url. Un ejemplo de esto que he encontrado (pero no puedo recordar dónde dar crédito) es

//Create a stream for the file 
    Stream stream = null; 

    //This controls how many bytes to read at a time and send to the client 
    int bytesToRead = 10000; 

    // Buffer to read bytes in chunk size specified above 
    byte[] buffer = new Byte[bytesToRead]; 

    // The number of bytes read 
    try 
    { 
     //Create a WebRequest to get the file 
     HttpWebRequest fileReq = (HttpWebRequest) HttpWebRequest.Create(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 = fileResp.GetResponseStream(); 

     // 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"; 

     //Name the file 
     resp.AddHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); 
     resp.AddHeader("Content-Length", fileResp.ContentLength.ToString()); 

     int length; 
     do 
     { 
      // Verify that the client is connected. 
      if (resp.IsClientConnected) 
      { 
       // Read data into the buffer. 
       length = stream.Read(buffer, 0, bytesToRead); 

       // and write it out to the response's output stream 
       resp.OutputStream.Write(buffer, 0, length); 

       // Flush the data 
       resp.Flush(); 

       //Clear the buffer 
       buffer = new Byte[bytesToRead]; 
      } 
      else 
      { 
       // cancel the download if client has disconnected 
       length = -1; 
      } 
     } while (length > 0); //Repeat until no data is read 
    } 
    finally 
    { 
     if (stream != null) 
     { 
      //Close the input stream 
      stream.Close(); 
     } 
    } 
+2

No es necesario enjuagar la respuesta y volver a crear el búfer cada ejecución: ralentizará la transferencia.Además, creo que debería cambiar el nombre de algunas de las variables (fileReq -> urlRequest, fileResp -> urlResponse). Además, no hay ninguna razón para crear la variable Stream, al principio, debe crearla donde la usa (cerca de la llamada GetResponseStream()) – data

+0

@data_smith ¿Por qué no prueba lo que está sugiriendo? No compilará Y el propósito del búfer es mantener el uso de memoria en el servidor web. – Paparazzi

+3

resp no está definido en este ejemplo: el código no se compila. – Case

-2

Usted podría tratar de usar la clase DirectoryEntry con el prefijo de ruta de IIS:

using(DirectoryEntry de = new DirectoryEntry("IIS://Localhost/w3svc/1/root" + DOCUMENT_PATH)) 
{ 
    filePath = de.Properties["Path"].Value; 
} 

if (!File.Exists(filePath)) 
     return; 

var fileInfo = new System.IO.FileInfo(filePath); 
Response.ContentType = "application/octet-stream"; 
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", filePath)); 
Response.AddHeader("Content-Length", fileInfo.Length.ToString()); 
Response.WriteFile(filePath); 
Response.End(); 
3

2 años más tarde, se utiliza la respuesta de Dallas, pero tuve que cambiar el HttpWebRequest a FileWebRequest ya que estaba ligarse a archivos directos. No estoy seguro de si este es el caso en todas partes, pero pensé que lo agregaría. Además, me quité

var resp = Http.Current.Resonse

y acabo de utilizar Http.Current.Response en el lugar donde se hace referencia resp.

+1

Perfecto. Deshice la respuesta de Dalla un poco. Estoy publicando mi versión debajo de –

12

Hago esto bastante y pensé que podría agregar una respuesta más simple. Lo configuré como una clase simple aquí, pero lo ejecuto todas las noches para recopilar datos financieros de las empresas que estoy siguiendo.

class WebPage 
{ 
    public static string Get(string uri) 
    { 
     string results = "N/A"; 

     try 
     { 
      HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri); 
      HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); 

      StreamReader sr = new StreamReader(resp.GetResponseStream()); 
      results = sr.ReadToEnd(); 
      sr.Close(); 
     } 
     catch (Exception ex) 
     { 
      results = ex.Message; 
     } 
     return results; 
    } 
} 

En este caso, paso una url y devuelve la página como HTML. Si quieres hacer algo diferente con la transmisión, puedes cambiar esto fácilmente.

que lo utilice como esto:

string page = WebPage.Get("http://finance.yahoo.com/q?s=yhoo"); 
+0

mi caso es diferente, hay un sistema de administración de documentos y devuelve documentos en formato .tif donde no se envía en querystring. Ejemplo: [link] (http://1.2.3.4/docsys/getdocuments.aspx?doc=DSF16-00260132) pero este método no funciona, cualquier idea es apreciada. gracias –

+0

@ kayhanyüksel: probé ese enlace pero se agotó el tiempo de espera. Lo siento. – CodeChops

7

Descargar url para bytes y convertir bytes en la secuencia:

using (var client = new WebClient()) 
{ 
    var content = client.DownloadData(url); 
    using (var stream = new MemoryStream(content)) 
    { 
     ... 
    } 
} 
+0

La respuesta más simple, y funciona. Gracias – buffjape

+0

Aunque esto parece ser simple y funciona bien, pero debe tener en cuenta que esta solución carga el archivo en la memoria de su computadora. Por lo tanto, es probable que obtenga una excepción debido a que la memoria insuficiente es alta cuando: 1) los datos son demasiado grandes o 2) las solicitudes múltiples se realizan simultáneamente. – Benjamin