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);
}
Mes 2 cents - vous n'avez pas besoin de stocker l'Excel en tant que fichier physique sur le serveur - à la place, stockez-le dans le cache (Session). Utilisez un nom généré de manière unique pour votre variable Cache (qui stocke ce fichier Excel) - ce sera le retour de votre appel ajax (initial). De cette façon, vous n'avez pas à gérer les problèmes d'accès aux fichiers, à gérer (supprimer) les fichiers lorsqu'ils ne sont pas nécessaires, etc. et, avoir le fichier dans le cache, il est plus rapide de le récupérer.
la source
J'ai récemment pu accomplir cela dans MVC (bien qu'il n'y ait pas eu besoin d'utiliser AJAX) sans créer de fichier physique et j'ai pensé partager mon code:
Fonction JavaScript super simple (le clic sur le bouton datatables.net déclenche ceci):
Code du contrôleur C #:
Dans la classe ExportHelper, j'utilise un outil tiers ( GemBox.Spreadsheet ) pour générer le fichier Excel et il dispose d'une option Enregistrer dans le flux. Cela étant dit, il existe un certain nombre de façons de créer des fichiers Excel qui peuvent facilement être écrits dans un flux mémoire.
Dans IE, Chrome et Firefox, le navigateur vous invite à télécharger le fichier et aucune navigation réelle ne se produit.
la source
Créez d'abord l'action du contrôleur qui créera le fichier Excel
puis créez l'action Télécharger
si vous souhaitez supprimer le fichier après le téléchargement, créez-le
et enfin appel ajax de votre vue MVC Razor
la source
J'ai utilisé la solution publiée par CSL mais je vous recommande de ne pas stocker les données du fichier dans Session pendant toute la session. En utilisant TempData, les données du fichier sont automatiquement supprimées après la demande suivante (qui est la demande GET pour le fichier). Vous pouvez également gérer la suppression des données de fichier dans Session lors de l'action de téléchargement.
La session peut consommer beaucoup de mémoire / d'espace en fonction du stockage SessionState et du nombre de fichiers exportés pendant la session et si vous avez de nombreux utilisateurs.
J'ai mis à jour le code côté sereur de CSL pour utiliser TempData à la place.
la source
en utilisant ClosedXML.Excel;
la source
la source
La réponse acceptée n'a pas tout à fait fonctionné pour moi car j'ai obtenu un résultat 502 Bad Gateway de l'appel ajax même si tout semblait bien revenir du contrôleur.
Peut-être que j'atteignais une limite avec TempData - pas sûr, mais j'ai trouvé que si j'utilisais IMemoryCache au lieu de TempData , cela fonctionnait bien, voici donc ma version adaptée du code dans la réponse acceptée:
L'appel AJAX reste comme avec la réponse acceptée (je n'ai fait aucun changement):
L'action du contrôleur pour gérer le téléchargement du fichier:
...
Il y a maintenant un code supplémentaire pour configurer MemoryCache ...
Afin d'utiliser "_cache", j'ai injecté dans le constructeur pour le contrôleur comme ceci:
Et assurez-vous que vous disposez des éléments suivants dans ConfigureServices dans Startup.cs:
la source
Ce fil de discussion m'a aidé à créer ma propre solution que je partagerai ici. J'utilisais une demande GET ajax au début sans problèmes, mais cela est arrivé à un point où la longueur de l'URL de la demande était dépassée, j'ai donc dû passer à un POST.
Le javascript utilise le plugin de téléchargement de fichier JQuery et se compose de 2 appels successifs. Un POST (pour envoyer des paramètres) et un GET pour récupérer le fichier.
Du côté serveur
la source
La réponse de CSL a été implémentée dans un projet sur lequel je travaille, mais le problème que j'ai rencontré était la mise à l'échelle sur Azure a interrompu nos téléchargements de fichiers. Au lieu de cela, j'ai pu le faire avec un seul appel AJAX:
SERVEUR
CLIENT (version modifiée du téléchargement du fichier Handle à partir du post ajax )
la source
la source
Je peux sembler tout à fait naïf, et peut attirer tout à fait critique, mais voici comment je l' ai fait,
( il ne comporte pas
ajax
pour l' exportation, mais il ne fait pas une publication complète soit )Merci pour ce post et cette réponse.
Créer un contrôleur simple
Et voici les vues ..
Le but de l' astuce semble que, nous publions un formulaire (une partie de la vue Razor) sur lequel nous appelons an
Action method
, qui retourne: aFileResult
, et celaFileResult
retournethe Excel File
..Et pour afficher les valeurs de filtre, comme dit, ( et si vous le souhaitez), je fais une demande de publication pour une autre action, comme cela a été tenté de le décrire.
la source
J'utilise Asp.Net WebForm et je veux juste télécharger un fichier côté serveur. Il y a beaucoup d'articles mais je ne trouve pas de réponse simple. Maintenant, j'ai essayé une méthode basique et je l'ai obtenue.
C'est mon problème.
Je dois créer de nombreux boutons d'entrée de manière dynamique au moment de l'exécution. Et je veux ajouter chaque bouton au bouton de téléchargement en donnant un numéro de fichier unique.
Je crée chaque bouton comme ceci:
Chaque bouton appelle cette méthode ajax.
Ensuite, j'ai écrit une méthode simple de base.
Je génère ce Form_1, Form_2, Form_3 .... Et je vais supprimer ces anciens fichiers avec un autre programme. Mais s'il existe un moyen d'envoyer simplement un tableau d'octets pour télécharger un fichier, comme en utilisant Response. Je veux l'utiliser.
J'espère que ce sera utile pour n'importe qui.
la source
Sur Soumettre le formulaire
la source