Vous ne pouvez pas renvoyer directement un fichier à télécharger via un appel AJAX.Une approche alternative consiste donc à utiliser un appel AJAX pour publier les données associées sur votre serveur. Vous pouvez ensuite utiliser le code côté serveur pour créer le fichier Excel (je recommanderais d'utiliser EPPlus ou NPOI pour cela, même si cela semble que cette partie fonctionne).
MISE À JOUR Septembre 2016
Ma réponse originale (ci-dessous) avait plus de 3 ans, j'ai donc pensé que je mettrais à jour car je ne crée plus de fichiers sur le serveur lors du téléchargement de fichiers via AJAX, cependant, j'ai laissé la réponse originale car elle peut être d'une certaine utilité en fonction de vos besoins spécifiques.
Un scénario courant dans mes applications MVC consiste à générer des rapports via une page Web contenant certains paramètres de rapport configurés par l'utilisateur (plages de dates, filtres, etc.). Lorsque l'utilisateur a spécifié les paramètres qu'il publie sur le serveur, le rapport est généré (par exemple, un fichier Excel en sortie), puis je stocke le fichier résultant sous forme de tableau d'octets dans le TempData
seau avec une référence unique. Cette référence est renvoyée en tant que résultat Json à ma fonction AJAX qui redirige ensuite vers une action de contrôleur distincte pour extraire les données TempData
et les télécharger vers le navigateur de l'utilisateur final.
Pour donner plus de détails, en supposant que vous ayez une vue MVC dont le formulaire est lié à une classe Model, appelons le modèle ReportVM
.
Tout d'abord, une action du contrôleur est nécessaire pour recevoir le modèle publié, un exemple serait:
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" }
};
}
L'appel AJAX qui publie mon formulaire MVC sur le contrôleur ci-dessus et reçoit la réponse ressemble à ceci:
$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;
}
})
L'action du contrôleur pour gérer le téléchargement du fichier:
[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();
}
}
Un autre changement qui pourrait facilement être adapté si nécessaire est de passer le type MIME du fichier en tant que troisième paramètre afin que l'action d'un contrôleur puisse correctement servir une variété de formats de fichier de sortie.
Cela supprime tout besoin de créer et de stocker des fichiers physiques sur le serveur, de sorte qu'aucune routine de maintenance n'est requise et encore une fois, cela est transparent pour l'utilisateur final.
Notez que l'avantage d'utiliser TempData
plutôt que Session
c'est qu'une fois TempData
lues, les données sont effacées, ce qui sera plus efficace en termes d'utilisation de la mémoire si vous avez un volume élevé de demandes de fichiers. Voir les meilleures pratiques TempData .
Réponse ORIGINALE
Vous ne pouvez pas renvoyer directement un fichier à télécharger via un appel AJAX.Une approche alternative consiste donc à utiliser un appel AJAX pour publier les données associées sur votre serveur. Vous pouvez ensuite utiliser le code côté serveur pour créer le fichier Excel (je recommanderais d'utiliser EPPlus ou NPOI pour cela, même si cela semble que cette partie fonctionne).
Une fois que le fichier a été créé sur le serveur, renvoyez le chemin d'accès au fichier (ou simplement le nom de fichier) comme valeur de retour à votre appel AJAX, puis définissez le JavaScript window.location
sur cette URL qui invitera le navigateur à télécharger le fichier.
Du point de vue des utilisateurs finaux, l'opération de téléchargement de fichier est transparente car ils ne quittent jamais la page d'où provient la demande.
Vous trouverez ci-dessous un exemple simple d'appels ajax pour y parvenir:
$.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;
}
});
- Le paramètre url est la méthode Controller / Action dans laquelle votre code créera le fichier Excel.
- Le paramètre data contient les données json qui seraient extraites du formulaire.
- returnValue serait le nom de fichier de votre fichier Excel nouvellement créé.
- La commande window.location redirige vers la méthode Controller / Action qui renvoie réellement votre fichier pour téléchargement.
Un exemple de méthode de contrôleur pour l'action de téléchargement serait:
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}