2008-10-09 5 views
3

J'ai un site Web asp.net qui permet à l'utilisateur de télécharger des fichiers volumineux - de 30 Mo à environ 60 Mo. Parfois, le téléchargement fonctionne bien, mais il échoue souvent à un moment donné avant que le téléchargement ne se termine avec le message indiquant que la connexion avec le serveur a été réinitialisée. À l'origine, j'utilisais simplement Server.TransmitFile mais après avoir lu un peu, j'utilise maintenant le code affiché ci-dessous. Je définis également la valeur Server.ScriptTimeout à 3600 dans l'événement Page_Init.Téléchargement de fichiers volumineux - Connexion avec réinitialisation du serveur

private void DownloadFile(string fname, bool forceDownload) 
     { 
      string path = MapPath(fname); 
      string name = Path.GetFileName(path); 
      string ext = Path.GetExtension(path); 
      string type = ""; 

      // set known types based on file extension 

      if (ext != null) 
      { 
       switch (ext.ToLower()) 
       { 
        case ".mp3": 
         type = "audio/mpeg"; 
         break; 

        case ".htm": 
        case ".html": 
         type = "text/HTML"; 
         break; 

        case ".txt": 
         type = "text/plain"; 
         break; 

        case ".doc": 
        case ".rtf": 
         type = "Application/msword"; 
         break; 
       } 
      } 

      if (forceDownload) 
      { 
       Response.AppendHeader("content-disposition", 
        "attachment; filename=" + name.Replace(" ", "_")); 
      } 

      if (type != "") 
      { 
       Response.ContentType = type; 
      } 
      else 
      { 
       Response.ContentType = "application/x-msdownload"; 
      } 

      System.IO.Stream iStream = null; 

      // Buffer to read 10K bytes in chunk: 
      byte[] buffer = new Byte[10000]; 

      // Length of the file: 
      int length; 

      // Total bytes to read: 
      long dataToRead; 

      try 
      { 
       // Open the file. 
       iStream = new System.IO.FileStream(path, System.IO.FileMode.Open, 
          System.IO.FileAccess.Read, System.IO.FileShare.Read); 


       // Total bytes to read: 
       dataToRead = iStream.Length; 

       //Response.ContentType = "application/octet-stream"; 
       //Response.AddHeader("Content-Disposition", "attachment; filename=" + filename); 

       // Read the bytes. 
       while (dataToRead > 0) 
       { 
        // Verify that the client is connected. 
        if (Response.IsClientConnected) 
        { 
         // Read the data in buffer. 
         length = iStream.Read(buffer, 0, 10000); 

         // Write the data to the current output stream. 
         Response.OutputStream.Write(buffer, 0, length); 

         // Flush the data to the HTML output. 
         Response.Flush(); 

         buffer = new Byte[10000]; 
         dataToRead = dataToRead - length; 
        } 
        else 
        { 
         //prevent infinite loop if user disconnects 
         dataToRead = -1; 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       // Trap the error, if any. 
       Response.Write("Error : " + ex.Message); 
      } 
      finally 
      { 
       if (iStream != null) 
       { 
        //Close the file. 
        iStream.Close(); 
       } 
       Response.Close(); 
      } 

     } 

Répondre

0

Le correctif final pour ce problème consistait à apporter une modification dans le fichier web.config. J'ai simplement dû changer le mode sessionState = "InProc" en mode sessionState = "StateServer".

+0

Pourquoi? Pourriez-vous s'il vous plaît expliquer la raison? –

2

Est-ce

<configuration> 
    <system.web> 
    <httpRuntime executionTimeout="3600"/> 
    </system.web> 
</configuration> 

quoi que ce soit d'aide?

La boucle intérieure qui écrit les données semble un peu alambiquée, je au moins changer à:

int length; 
while( Response.IsClientConnected && 
     (length=iStream.Read(buffer,0,buffer.Length))>0) 
{ 
    Response.OutputStream.Write(buffer,0,length); 
    Response.Flush(); 
} 

Il n'y a pas besoin de réaffecter le tampon à chaque tour dans la boucle, vous pouvez simplement re utilisez-le après l'avoir écrit en sortie.

Une amélioration supplémentaire consisterait à utiliser une E/S asynchrone mais pour un autre jour.

+0

La modification de l'heure d'exécution n'a pas fonctionné pour moi. –

2

J'ai rencontré un problème similaire lorsque j'utilisais FileUpload Control et que je téléchargeais une taille de fichier> 4 Mo. J'avais l'habitude d'obtenir la page d'erreur «La connexion a été réinitialisée». Et cela les étapes que j'ai suivies pour résoudre le problème:

Accédez au fichier web.config et définissez une taille limite appropriée pour les types de fichiers que vous souhaitez télécharger. La limite de taille par défaut est 4096 kilo-octets (Ko) ou 4 mégaoctets (Mo). Vous pouvez autoriser le téléchargement de fichiers volumineux en définissant l'attribut maxRequestLength de l'élément httpRuntime. Pour augmenter la taille de fichier maximale autorisée pour l'ensemble de l'application, définissez l'attribut maxRequestLength dans le fichier Web.config.

Par exemple, pour permettre à 10MB (10240 KB) file..I utilisé (REPLACE '[' avec '<' et ']' avec '>')

[configuration]
[system.web]
[httpRuntime maxRequestLength = "10240" /]
[/system.web]
[/ configuration]

0

ce qui a fini par travailler pour moi est en train de faire un Response.End et de faire également une déclaration en utilisant le flux de fichiers . Voici le code que j'ai:

public partial class ssl_Report_StreamReport : BaseReportPage 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     //Get the parameters 
     string reportName = Utils.ParseStringRequest(Request, "reportName") ?? string.Empty; 
     string reportGuid = Session["reportGuid"].ToString(); 
     string path = Path.Combine(ReportPath(), Utils.GetSessionReportName(reportName, reportGuid)); 

     using (var fileStream = File.Open(path, FileMode.Open)) 
     { 
      Response.ClearHeaders(); 
      Response.Clear(); 
      Response.ContentType = "application/octet-stream"; 
      Response.AddHeader("Content-Disposition", "attachment; filename=\"" + reportName + "\""); 
      Response.AddHeader("Content-Length", fileStream.Length.ToString(CultureInfo.InvariantCulture)); 
      StreamHelper.CopyStream(fileStream, Response.OutputStream); 
      Response.Flush(); 
      Response.End(); 
     } 

     ReportProcessor.ClearReport(Session.SessionID, path); 
    } 
} 


public static class StreamHelper 
{ 
    public static void CopyStream(Stream input, Stream output) 
    { 
     byte[] buffer = new byte[32768]; 
     int read; 
     while ((read = input.Read(buffer, 0, buffer.Length)) > 0) 
     { 
      output.Write(buffer, 0, read); 
     } 
    } 
} 
Questions connexes