Sie können eine Datei nicht direkt über einen AJAX-Aufruf zum Herunterladen zurückgeben. Ein alternativer Ansatz besteht darin, einen AJAX-Aufruf zu verwenden, um die zugehörigen Daten auf Ihrem Server zu veröffentlichen. Sie können dann serverseitigen Code verwenden, um die Excel-Datei zu erstellen (ich würde empfehlen, dafür EPPlus oder NPOI zu verwenden, obwohl es so klingt, als ob dieser Teil funktioniert).
UPDATE September 2016
Meine ursprüngliche Antwort (unten) war über 3 Jahre alt, daher dachte ich, ich würde sie aktualisieren, da ich beim Herunterladen von Dateien über AJAX keine Dateien mehr auf dem Server erstelle. Ich habe jedoch die ursprüngliche Antwort belassen, da sie möglicherweise noch von Nutzen ist Ihre spezifischen Anforderungen.
Ein häufiges Szenario in meinen MVC-Anwendungen ist die Berichterstellung über eine Webseite mit einigen vom Benutzer konfigurierten Berichtsparametern (Datumsbereiche, Filter usw.). Wenn der Benutzer die Parameter angegeben hat, die er an den Server sendet, wird der Bericht generiert (z. B. eine Excel-Datei als Ausgabe), und dann speichere ich die resultierende Datei als Byte-Array im TempData
Bucket mit einer eindeutigen Referenz. Diese Referenz wird als Json-Ergebnis an meine AJAX-Funktion zurückgegeben, die anschließend zu einer separaten Controller-Aktion umleitet, um die Daten aus TempData
dem Browser des Endbenutzers zu extrahieren und in diesen herunterzuladen.
Um dies näher zu erläutern, rufen wir das Modell auf, vorausgesetzt, Sie haben eine MVC-Ansicht, deren Formular an eine Modellklasse gebunden ist ReportVM
.
Zunächst ist eine Controller-Aktion erforderlich, um das veröffentlichte Modell zu erhalten. Ein Beispiel wäre:
public ActionResult PostReportPartial(ReportVM model){
// Validate the Model is correct and contains valid data
// Generate your report output based on the model parameters
// This can be an Excel, PDF, Word file - whatever you need.
// As an example lets assume we've generated an EPPlus ExcelPackage
ExcelPackage workbook = new ExcelPackage();
// Do something to populate your workbook
// Generate a new unique identifier against which the file can be stored
string handle = Guid.NewGuid().ToString();
using(MemoryStream memoryStream = new MemoryStream()){
workbook.SaveAs(memoryStream);
memoryStream.Position = 0;
TempData[handle] = memoryStream.ToArray();
}
// Note we are returning a filename as well as the handle
return new JsonResult() {
Data = new { FileGuid = handle, FileName = "TestReportOutput.xlsx" }
};
}
Der AJAX-Aufruf, der mein MVC-Formular an den oben genannten Controller sendet und die Antwort empfängt, sieht folgendermaßen aus:
$ajax({
cache: false,
url: '/Report/PostReportPartial',
data: _form.serialize(),
success: function (data){
var response = JSON.parse(data);
window.location = '/Report/Download?fileGuid=' + response.FileGuid
+ '&filename=' + response.FileName;
}
})
Die Controller-Aktion zum Herunterladen der Datei:
[HttpGet]
public virtual ActionResult Download(string fileGuid, string fileName)
{
if(TempData[fileGuid] != null){
byte[] data = TempData[fileGuid] as byte[];
return File(data, "application/vnd.ms-excel", fileName);
}
else{
// Problem - Log the error, generate a blank file,
// redirect to another controller action - whatever fits with your application
return new EmptyResult();
}
}
Eine weitere Änderung, die bei Bedarf problemlos vorgenommen werden kann, besteht darin, den MIME-Typ der Datei als dritten Parameter zu übergeben, damit die eine Controller-Aktion eine Vielzahl von Ausgabedateiformaten korrekt bedienen kann.
Auf diese Weise müssen keine physischen Dateien mehr erstellt und auf dem Server gespeichert werden, sodass keine Reinigungsroutinen erforderlich sind. Dies ist wiederum für den Endbenutzer nahtlos.
Beachten Sie, dass der Vorteil der Verwendung TempData
und nicht darin Session
besteht, dass TempData
die Daten nach dem Lesen gelöscht werden, sodass die Speichernutzung effizienter ist, wenn Sie eine große Anzahl von Dateianforderungen haben. Siehe TempData Best Practice .
ORIGINAL Antwort
Sie können eine Datei nicht direkt über einen AJAX-Aufruf zum Herunterladen zurückgeben. Ein alternativer Ansatz besteht darin, einen AJAX-Aufruf zu verwenden, um die zugehörigen Daten auf Ihrem Server zu veröffentlichen. Sie können dann serverseitigen Code verwenden, um die Excel-Datei zu erstellen (ich würde empfehlen, dafür EPPlus oder NPOI zu verwenden, obwohl es so klingt, als ob dieser Teil funktioniert).
Nachdem die Datei auf dem Server erstellt wurde, geben Sie den Pfad zur Datei (oder nur den Dateinamen) als Rückgabewert für Ihren AJAX-Aufruf zurück und setzen Sie das JavaScript window.location
auf diese URL, die den Browser zum Herunterladen der Datei auffordert.
Aus Sicht der Endbenutzer ist der Dateidownload-Vorgang nahtlos, da sie die Seite, von der die Anforderung stammt, nie verlassen.
Im Folgenden finden Sie ein einfaches Beispiel für einen Ajax-Aufruf, um dies zu erreichen:
$.ajax({
type: 'POST',
url: '/Reports/ExportMyData',
data: '{ "dataprop1": "test", "dataprop2" : "test2" }',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (returnValue) {
window.location = '/Reports/Download?file=' + returnValue;
}
});
- Der Parameter url ist die Controller / Action-Methode, mit der Ihr Code die Excel-Datei erstellt.
- Der Datenparameter enthält die JSON-Daten, die aus dem Formular extrahiert werden würden.
- returnValue ist der Dateiname Ihrer neu erstellten Excel-Datei.
- Der Befehl window.location leitet zur Controller / Action-Methode weiter, die Ihre Datei tatsächlich zum Download zurückgibt.
Eine Beispiel-Controller-Methode für die Download-Aktion wäre:
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}
Meine 2 Cent - Sie müssen das Excel nicht als physische Datei auf dem Server speichern - speichern Sie es stattdessen im (Sitzungs-) Cache. Verwenden Sie einen eindeutig generierten Namen für Ihre Cache-Variable (in der diese Excel-Datei gespeichert ist). Dies ist die Rückgabe Ihres (anfänglichen) Ajax-Aufrufs. Auf diese Weise müssen Sie sich nicht mit Dateizugriffsproblemen befassen, die Dateien verwalten (löschen), wenn sie nicht benötigt werden usw., und wenn Sie die Datei im Cache haben, können Sie sie schneller abrufen.
quelle
Ich konnte dies kürzlich in MVC erreichen (obwohl AJAX nicht verwendet werden musste), ohne eine physische Datei zu erstellen, und dachte, ich würde meinen Code freigeben:
Super einfache JavaScript-Funktion (das Klicken auf die Schaltfläche datatables.net löst dies aus):
C # Controller-Code:
In der ExportHelper-Klasse verwende ich ein Drittanbieter-Tool ( GemBox.Spreadsheet ), um die Excel-Datei zu generieren, und es verfügt über die Option In Stream speichern. Abgesehen davon gibt es eine Reihe von Möglichkeiten, Excel-Dateien zu erstellen, die einfach in einen Speicherstrom geschrieben werden können.
In IE, Chrome und Firefox fordert der Browser zum Herunterladen der Datei auf, und es erfolgt keine tatsächliche Navigation.
quelle
Erstellen Sie zuerst die Controller-Aktion, mit der die Excel-Datei erstellt wird
Erstellen Sie dann die Download-Aktion
Wenn Sie die Datei nach dem Herunterladen löschen möchten, erstellen Sie diese
und schließlich Ajax Anruf von Ihnen MVC Razor Ansicht
quelle
Ich habe die von CSL bereitgestellte Lösung verwendet, aber ich würde empfehlen, die Dateidaten nicht während der gesamten Sitzung in der Sitzung zu speichern. Bei Verwendung von TempData werden die Dateidaten nach der nächsten Anforderung (der GET-Anforderung für die Datei) automatisch entfernt. Sie können auch das Entfernen der Dateidaten in Sitzung in Download-Aktion verwalten.
Die Sitzung kann viel Speicherplatz beanspruchen, abhängig vom SessionState-Speicher und der Anzahl der exportierten Dateien während der Sitzung und wenn Sie viele Benutzer haben.
Ich habe den sererseitigen Code von CSL aktualisiert, um stattdessen TempData zu verwenden.
quelle
using ClosedXML.Excel;
quelle
quelle
Die akzeptierte Antwort funktionierte für mich nicht ganz, da ich durch den Ajax-Anruf ein 502 Bad Gateway- Ergebnis erhielt, obwohl vom Controller alles in Ordnung zu sein schien.
Vielleicht habe ich mit TempData ein Limit erreicht - nicht sicher, aber ich habe festgestellt, dass es gut funktioniert hat , wenn ich IMemoryCache anstelle von TempData verwendet habe. Hier ist meine angepasste Version des Codes in der akzeptierten Antwort:
AJAX-Anruf bleibt wie bei der akzeptierten Antwort (ich habe keine Änderungen vorgenommen):
Die Controller-Aktion zum Herunterladen der Datei:
...
Jetzt gibt es einen zusätzlichen Code zum Einrichten von MemoryCache ...
Um "_cache" zu verwenden, habe ich den Konstruktor für den Controller wie folgt eingefügt:
Stellen Sie unter ConfigureServices in Startup.cs Folgendes sicher:
quelle
Dieser Thread hat mir geholfen, meine eigene Lösung zu erstellen, die ich hier teilen werde. Ich habe zunächst eine GET-Ajax-Anfrage ohne Probleme verwendet, aber es kam zu einem Punkt, an dem die Länge der Anforderungs-URL überschritten wurde, sodass ich zu einem POST wechseln musste.
Das Javascript verwendet das JQuery-Datei-Download-Plugin und besteht aus 2 aufeinander folgenden Aufrufen. Ein POST (zum Senden von Parametern) und ein GET zum Abrufen der Datei.
Serverseite
quelle
Die Antwort von CSL wurde in einem Projekt implementiert, an dem ich arbeite, aber das Problem, das ich beim Skalieren in Azure hatte, hat unsere Dateidownloads unterbrochen. Stattdessen konnte ich dies mit einem AJAX-Aufruf tun:
SERVER
CLIENT (modifizierte Version des Handle-Dateidownloads von Ajax Post )
quelle
quelle
Ich mag ziemlich naiv klingen und eine ziemliche Kritik auf mich ziehen, aber hier ist, wie ich es gemacht habe
( es beinhaltet keinen
ajax
Export, aber es macht auch kein vollständiges Postback )Danke für diesen Beitrag und diese Antwort.
Erstellen Sie eine einfache Steuerung
Und hier sind die Ansichten ..
Der ganze Sinn des Tricks scheint , dass wir ein Formular veröffentlichen (ein Teil der Razor - Ansicht) , auf das wir fordern ein
Action method
, die zurückkehrt: einFileResult
, und dieseFileResult
zurückkehrtthe Excel File
..Und die Filterwerte für die Buchung, wie gesagt, ( und wenn Sie es benötigen), mache ich eine Post-Anfrage zu einer anderen Aktion, wie versucht wurde zu beschreiben ..
quelle
Ich verwende Asp.Net WebForm und möchte nur eine Datei vom Server herunterladen. Es gibt viele Artikel, aber ich kann nicht nur eine grundlegende Antwort finden. Jetzt habe ich einen einfachen Weg ausprobiert und ihn verstanden.
Das ist mein Problem.
Ich muss zur Laufzeit viele Eingabeschaltflächen dynamisch erstellen. Und ich möchte jede Schaltfläche zum Herunterladen mit einer eindeutigen Dateinummer hinzufügen.
Ich erstelle jeden Button so:
Jede Schaltfläche ruft diese Ajax-Methode auf.
Dann habe ich eine einfache Methode geschrieben.
Ich generiere dieses Form_1, Form_2, Form_3 ... und ich werde diese alten Dateien mit einem anderen Programm löschen. Aber wenn es eine Möglichkeit gibt, nur ein Byte-Array zum Herunterladen von Dateien zu senden, wie mit Response. Ich möchte es benutzen.
Ich hoffe, dass dies für jeden nützlich sein wird.
quelle
Auf Formular senden
quelle