2016-02-11 19 views
6

Müşterilerimiz için farklı dosyalar sağlayan MVC 5 tabanlı bir WebAPI Denetleyicisi oluşturdum. Dosyalara erişme aracı da kendiliğinden yazılmıştır - .NET HttpClient'e dayanır - ama bu başka bir hikaye.MVC 5 WebAPI - Dosyaları İndirin - HttpException

Ben this

gibi dosyaları temin etmek mekanizmasında yapı kullandım indir kontrolörün ilk versiyonda

Ama bu mekanizma 4GB> dosyalar için benim IIS üzerinde düştü. Bu kod çok iyi çalışıyor

public class DownloadController : ApiController 
    { 
     public async Task Get(long id) 
     { 
      string fullFilePath = GetFilePathById(id); 
      string returnFileName = fullFilePath.Split('\\').Last(); 
      FileInfo path = new FileInfo(fullFilePath); 
      HttpContext.Current.Response.ContentType = "application/zip"; 
      HttpContext.Current.Response.AddHeader("Content-Length", path.Length.ToString()); 
      HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + returnFileName); 
      HttpContext.Current.Response.Flush(); 
     try 
     { 
      byte[] buffer = new byte[4096]; 
      using (FileStream fs = path.OpenRead()) 
      { 
       using (BufferedStream bs = new BufferedStream(fs, 524288)) 
       { 
        int count = 0; 
        while ((count = bs.Read(buffer, 0, buffer.Length)) > 0) 
        { 
         if (!HttpContext.Current.Response.IsClientConnected) 
         { 
          break; 
         } 
         HttpContext.Current.Response.OutputStream.Write(buffer, 0, count); 
         HttpContext.Current.Response.Flush(); 
        } 
       } 
      } 
     } 
     catch (Exception exception) 
     { 
      //Exception logging here 
     } 
    } 
} 

ve kabul edilebilir CPU kullanımı ve disk i/o ile hızlı indirme var:

Yani Sonunda bu kodun geldi. her indirme ile - - Ama bir süre sonra bunu fark işlenmeyen bir özel durum böyle IIS sunucusunun application eventlog içine bir girdi yazıyor:

Server cannot set status after HTTP headers have been sent 

Exception type: HttpException 

Event Log ID 1309 

eminim o .Flush yinelenen kullanımı() Soruna neden olur, ancak bunlardan herhangi birini kaldırırsanız, indirme işlemi durur.

Benzer sorularda, Response.BufferOutput = true;'u bir çözüm olarak bulabilirim, ancak tüm sunucu kaynaklarımı tüketiyor ve indirme işlemini geciktiriyor gibi görünüyor.

Herhangi bir öneri harika olurdu!

+1

Sonunda bir "HttpContext.Current.Response.Close()" eklemeyi denediniz mi? Veya, varsa (ve daha fazla işleme gerek yoktur), 'HttpContext.Current.ApplicationInstance.CompleteRequest()'? – Jcl

+0

StreamContent kullanmıyor olmanızın nedeni nedir? – martennis

+0

@Jcl Bunu deneyeceğim ve geri bildirim alacağım. – maltmann

cevap

1

sorun Flush() ile değil, ancak geçer böylece HttpContext.Current.Response.Close();

ile akarsu kendini tepkisini kapanış olmadığını ASP.NET çerçeve, sen eylem yönteminin içine ne yaptığını bilmez Her zamanki tesisat borusu üzerinden talep, bizim için gerekli tüm sıhhi tesisat yapar. Bunlardan biri, üstbilgileri ve HTTP durumunu istemciye göndermesidir. Ancak, çerçeve bunu yapmaya çalıştığında, üstbilgileri zaten belirlediniz ve gönderdiniz. Bunu önlemek için akışı kapatmalı ve yanıt akışını kapatarak işlemeyi kendiniz bitirmelisiniz.

+0

ile büyük dosya indirme olanakları sağlayan en iyi seçenek olarak görünüyor. HTTP başlıklarını göndermeyi nasıl engelleyebileceğime dair bir fikrim var mı? – maltmann

+0

Fiddler'da gönderilmekte olan başlıkları kontrol edebilir misiniz? – Tamas

+0

Başlıklar yalnızca bir kez gelir. Sunucu olay günlüklerini temiz tutmak için bu istisnayı genel olarak engelleme eğilimindeyim – maltmann