2013-03-11 7 views
16

Ich arbeite daran, wie CSV-Datei von ASP.NET Web API von jQuery Ajax Anruf herunterladen. Die CSV-Datei wird basierend auf dem benutzerdefinierten CsvFormatter dynamisch vom Web-API-Server generiert.Wie CSV-Datei von ASP.NET Web API mit jQuery Ajax Anruf herunterladen

Ajax von jQuery:

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

Auf dem Server wird die EmployeeCsvFormatter ähnlich mit folgenden Artikeln implementiert, abgeleitet von 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")); 
    } 
    ... 
} 

I auch Override-Verfahren hinzugefügt, um zeigen an, dass ich wie normale Download-Datei herunterladen möchte (kann die Download-Datei im Download sehen tab):

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"); 
} 

Aber es allerdings nicht funktioniert, ist die Download-Datei nicht in der Statusleiste oder in Download-Tab in Chrome zeigt, auch von Fiddler, ich kann es die Antwort sehe richtig scheint:

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 

Meine Methode von 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; 
} 

Es muss irgendwo falsch sein, die ich aus nicht herausgefunden haben. Wie kann ich es funktionieren lassen, indem ich CSV-Datei wie üblich herunterlade?

+2

kann nicht mit AJAX in Datei herunterladen. Umleiten Sie einfach Benutzer zu url 'window.location = url', wenn der Server den Download erzwingt, wird die aktuelle Seite nicht verlassen – charlietfl

+0

@charlietfl: Wie kann ich Accept Header auf diese Weise setzen? –

+0

Was erwarten Sie von 'accept header'? Kann Benutzer nicht zwingen, irgendetwas mit Download zu akzeptieren – charlietfl

Antwort

15

jQuery Plugin for Requesting Ajax-like File Downloads tut es ohne Ajax using a simple form submit.

Intern:

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

Es hat eine Ajax-Stil-Schnittstelle so von außen Sie es wie diese

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

Einen weiteren einfachen Ansatz anrufen:

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

Auf dem Server, MediaTypeMappings muss verwendet werden, indem ein weiterer Konstruktor hinzugefügt wird:

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

Dann fügen Sie diese Formatierer in Web Api-Konfiguration:

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

Wie füge ich Accept-Header auf diesem Weg hinzu? –

+0

Guter Punkt. Der Browser wird einen hinzufügen, fürchte ich. Sie könnten das Format in die URL setzen, wie dieses $ .download ('/ api/employees/csv', ''); 'oder als Parameter:' $ .download ('/ api/employees /', 'format = csv '); ' – flup

+3

Ah, funktioniert es aus der Box? Manchmal ist das Leben weniger kompliziert als man befürchtet! Wird die Antwort aktualisieren. – flup

1

Sie auch den Request-Header in beforeSend durch die xhr Modifizierung einstellen.

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

Als alternativer Ansatz kann man den Download auf Klick einen Anker() oder die Taste mit der URL an die API-Methode Verlangte gesetzt anbieten, die mit der Anlage reagiert.

In der CsvMediaTypeFormatter (Abgeleitet von System.Net.Http.Formatting.MediaTypeFormatter), zusätzlich zur Kartierung des Text/CSV-MIME-Typs wie oben in den Antworten gezeigt, fand ich die folgenden getan werden muss:

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"); 
     } 

Hinweis: Bei dem Stream zu schreiben, stellen Sie die Content-Length Header und denken Sie daran, Spülen Sie den Stream. Ich habe festgestellt, dass die zurückgegebene Antwort ohne einen Aufruf an Flush() es nicht erfolgreich zu dem Client zurückgibt, selbst wenn die richtige Inhaltslänge festgelegt worden ist.