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