5

Ho un regolatore di API Web che assomiglia a questo:Come scaricare file binario usando l'API Web ASP.net e Javascript?

using System; 
using System.Net; 
using System.Net.Http; 
using System.Net.Http.Headers; 
using System.Web.Http; 
using System.Threading.Tasks; 
using System.IO; 

    namespace APIIntegration.Controllers 
    { 
     public class TestController : ApiController 
     { 
      // http://localhost/api/test 
      [HttpGet]   
      public async Task<HttpResponseMessage> Get() 
      { 
       Stream stream = streamWith256Bytes;    
       HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);    
       result.Content = new StreamContent(stream); 
       result.Content.Headers.ContentLength = stream.Length;    
       result.Content.Headers.ContentType = 
        new MediaTypeHeaderValue("application/octet-stream"); 
       result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); 
       result.Content.Headers.ContentDisposition.FileName = "foo.bin"; 
       return result; 
      } 

      private static Stream streamWith256Bytes 
      { 
       get 
       { 
        MemoryStream stream = new MemoryStream(); 
        for (int i = 0; i <256 ; i++) 
        { 
         stream.WriteByte(Convert.ToByte(i)); 
        } 
        stream.Position = 0; 
        return stream; 
       } 
      } 
     } 
    } 

In breve, questo controller tenta di scaricare un file da 256 byte al browser. Inizialmente, sembra funzionare, ma quando viene esaminato il file scaricato, la dimensione è 512 byte invece dei 256 byte previsti e i caratteri non stampabili vengono spostati nel cestino.

Come posso modificare questo codice in modo che i dati binari possano essere scaricati correttamente?

Edit: Vorrei anche ricordare che ho visto una domanda simile qui: Problems with downloading pdf file from web api service dove il problema è stato risolto con l'aggiunta di un'intestazione Content-Length, ma che non ha risolto questo per me.

Modifica: Ho modificato il codice sorgente sopra per dare un esempio completo e funzionante di come riprodurre.

Modifica: Ho scoperto che il codice sopra funziona in realtà correttamente quando digito l'indirizzo nella barra degli indirizzi, ma quando si utilizza Javascript per avviare il download, è dove ho un problema.

+0

Penso che potrebbe essere una sfumatura di come funziona MemoryStream. Prova a compilare un Byte normale [] e a costruire il MemoryStream con esso invece di scrivere direttamente in un'istanza vuota. – Machinarius

risposta

4

Ho trovato una soluzione. Nel mio Javascript, ho usato Angular per avviare un download di file utilizzando il servizio $ http angolare. Per impostazione predefinita, questo servizio interpreta la risposta come testo. Ho dovuto dire ad Angular di interpretare la risposta come un blob, e questo ha risolto tutto.

Il mio codice di lavoro è simile al seguente:

function download(downloadUrl) { 
    $http({ 
     url: downloadUrl, 
     responseType: "blob" 
    }) 
    .then(function (response) { 
     var blob = new Blob([response.data], { type: "application/octet-stream" }); 
     saveAs(blob, "foo.bin"); 
    }, function (response) { 
     alert("error downloading file from " + downloadUrl); 
    }); 
} 
+0

responseType: "blob" !!!! – Pascal