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 envoyer les données correspondantes à votre serveur. Vous pouvez ensuite utiliser un code côté serveur pour créer le fichier Excel (je recommanderais d'utiliser EPPlus ou NPOI pour cela, même si vous semblez avoir déjà travaillé cette partie).
MISE À JOUR septembre 2016
Ma réponse originale (ci-dessous) datant de plus de 3 ans, j'ai pensé que je pourrais la mettre à 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 encore être utile en fonction de vos besoins spécifiques.
Un scénario courant dans mes applications MVC est la création de rapports via une page web qui a des paramètres de rapport configurés par l'utilisateur (plages de dates, filtres, etc.). Lorsque l'utilisateur a spécifié les paramètres, il les envoie au serveur, le rapport est généré (disons par exemple un fichier Excel comme sortie) et ensuite je stocke le fichier résultant comme un tableau d'octets dans le fichier TempData
avec une référence unique. Cette référence est renvoyée sous la forme d'un résultat Json à ma fonction AJAX qui redirige ensuite vers une action de contrôleur distincte pour extraire les données de la base de données. TempData
et le télécharger dans le navigateur de l'utilisateur final.
Pour donner plus de détails, supposons que vous avez une vue MVC qui a un formulaire lié à une classe Modèle, appelons le Modèle ReportVM
.
Tout d'abord, une action du contrôleur est nécessaire pour recevoir le modèle affiché, 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 envoie mon formulaire MVC au 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();
}
}
Une autre modification, qui pourrait facilement être prise en compte si nécessaire, consisterait à transmettre le type MIME du fichier en tant que troisième paramètre, de sorte que l'action du contrôleur puisse servir correctement une variété de formats de fichiers de sortie.
Ainsi, il n'est plus nécessaire de créer et de stocker des fichiers physiques sur le serveur. Aucune routine de gestion n'est donc requise et, une fois encore, l'utilisateur final bénéficie d'une transparence totale.
Notez que l'avantage d'utiliser TempData
plutôt que Session
est qu'une fois TempData
est lue, les données sont effacées. Cette méthode sera donc plus efficace en termes d'utilisation de la mémoire si vous avez un volume élevé de demandes de fichiers. Voir Meilleure pratique 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 envoyer les données correspondantes à votre serveur. Vous pouvez ensuite utiliser un code côté serveur pour créer le fichier Excel (je recommanderais d'utiliser EPPlus ou NPOI pour cela, même si vous semblez avoir déjà travaillé cette partie).
Une fois que le fichier a été créé sur le serveur, renvoyez le chemin d'accès au fichier (ou simplement le nom du fichier) comme valeur de retour de votre appel AJAX, puis définissez les paramètres JavaScript suivants window.location
à cette URL qui invitera le navigateur à télécharger le fichier.
Du point de vue de l'utilisateur final, l'opération de téléchargement du fichier est transparente car il ne quitte jamais la page d'origine de la demande.
Vous trouverez ci-dessous un exemple simple et artificiel d'un appel 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;
}
});
-
url est la méthode du contrôleur/action où votre code créera le fichier Excel.
-
données contient les données json qui seront extraites du formulaire.
-
Valeur de retour serait le nom de fichier de votre fichier Excel nouvellement créé.
- Le site emplacement de la fenêtre redirige vers la méthode Contrôleur/Action qui renvoie effectivement votre fichier à télécharger.
Un exemple de méthode de contrôle pour l'action Télécharger serait :
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}