2013-03-11 5 views
16

Sto lavorando su come scaricare il file CSV da ASP.NET Web Api dalla chiamata jQuery ajax. Il file CSV viene generato dinamicamente dal server API Web basato su CsvFormatter personalizzato.Come scaricare il file CSV da ASP.NET Web Api utilizzando jQuery Ajax chiama

Ajax da jQuery:

$.ajax({ 
     type: "GET", 
     headers: { 
      Accept: "text/csv; charset=utf-8", 
     }, 
     url: "/api/employees", 
     success: function (data) { 
     } 
    }); 

Sul server, il EmployeeCsvFormatter è implementato simile con in basso l'articolo, derivato da BufferedMediaTypeFormatter:

http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

public class EmployeeCsvFormatter : BufferedMediaTypeFormatter 
{ 
    public EmployeeCsvFormatter() 
    { 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv")); 
    } 
    ... 
} 

Ho anche aggiunto metodo di sostituzione di indicare che mi piacerebbe scaricare come in un modo normale per scaricare il file (può vedere il download del file in download scheda):

public override void SetDefaultContentHeaders(Type type, 
    HttpContentHeaders headers, MediaTypeHeaderValue mediaType)  
{ 
    base.SetDefaultContentHeaders(type, headers, mediaType); 
    headers.Add("Content-Disposition", "attachment; filename=yourname.csv"); 
    headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
} 

Ma non funziona, il file di download non ha mostrato nella barra di stato o nella scheda scaricare su Chrome, anche se da Fiddler, vedo la risposta sembra corretto:

HTTP/1.1 200 OK 
Server: ASP.NET Development Server/11.0.0.0 
Date: Mon, 11 Mar 2013 08:19:35 GMT 
X-AspNet-Version: 4.0.30319 
Content-Disposition: attachment; filename=yourname.csv 
Cache-Control: no-cache 
Pragma: no-cache 
Expires: -1 
Content-Type: application/octet-stream 
Content-Length: 26 
Connection: Close 

1,Cuong,123 
1,Trung,123 

Il mio metodo da ApiController:

public EmployeeDto[] Get() 
{ 
    var result = new[] 
       { 
        new EmployeeDto() {Id = 1, Name = "Cuong", Address = "123"}, 
        new EmployeeDto() {Id = 1, Name = "Trung", Address = "123"}, 
       }; 

    return result; 
} 

Si deve essere da qualche parte sbagliata che non ho capito. Come posso farlo funzionare scaricando il file CSV come normale?

+2

non può scaricare su file con AJAX. Basta reindirizzare l'utente a url 'window.location = url', se il server forza il download non lascerà la pagina corrente – charlietfl

+0

@charlietfl: come posso impostare l'intestazione Accept in questo modo? –

+0

cosa ti aspetti con 'accept header'? Non è possibile forzare l'utente ad accettare nulla con download – charlietfl

risposta

15

jQuery Plugin for Requesting Ajax-like File Downloads lo fa senza Ajax using a simple form submit.

Internamente:

jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>') 
    .appendTo('body').submit().remove() 

Ha un'interfaccia Ajax-style in modo da fuori si può chiamare in questo modo

$.download('/api/employees','format=csv'); 

Un altro approccio semplice utilizzo:

$('#btnDownload').click(function (e) { 
    e.preventDefault(); 
    window.location = "/api/employees?format=csv"; 
}); 

Sul server, MediaTypeMappings deve essere utilizzato aggiungendo un altro costruttore:

public EmployeeCsvFormatter(MediaTypeMapping mediaTypeMapping) 
     : this() 
    { 
     MediaTypeMappings.Add(mediaTypeMapping); 
    } 

Quindi, aggiungere questo formattatore nella configurazione Api Web:

configuration.Formatters.Add(new EmployeeCsvFormatter 
      (new QueryStringMapping("format", "csv", "text/csv"))); 
+3

Come si aggiunge Accept intestazione in questo modo? –

+0

Buon punto. Il browser ne aggiungerà uno, temo. Puoi inserire il formato nell'URL, ad esempio '$ .download ('/ api/employees/csv', ''))' o come parametro: '$ .download ('/ api/employee /', 'format = csv '); ' – flup

+3

Ah, funziona fuori dalla scatola? a volte la vita è meno complicata di una paura! Aggiornerà la risposta. – flup

1

È inoltre possibile impostare l'intestazione della richiesta in beforeSend modificando il XHR.

$.ajax({ 
    url: "/api/employees", 
    type: "GET", 
    beforeSend: function (xhr) { 
     xhr.setRequestHeader("Accept", "text/csv"); 
    }, 
    success: function (data) { 
      } 
    }); 
3

Come approccio alternativo, si può offrire il download al clic di un ancoraggio() o il pulsante con l'URL richiesto impostato sul metodo API che risponde con l'allegato.

Nel CsvMediaTypeFormatter (derivato da System.Net.Http.Formatting.MediaTypeFormatter), in aggiunta alla mappatura del tipo MIME text/csv come mostrato nelle risposte di cui sopra, ho trovato i seguenti deve essere fatto:

public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType) 
     { 
      base.SetDefaultContentHeaders(type, headers, mediaType); 
      headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") 
      { 
       FileName = string.Concat("data", DateTime.UtcNow.ToString("yyyyMMddhhmmss"), ".csv") 
      }; 

      headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
     } 

Nota: Durante la scrittura del torrente, impostare l'intestazione Content-Length e ricordarsi di Flush il flusso. Ho trovato che senza una chiamata a Flush(), la risposta restituita non ritorna al client correttamente anche quando è stata impostata la lunghezza del contenuto corretta.

Problemi correlati