Exporter au format CSV en utilisant MVC, C # et jQuery

85

J'essaye d'exporter une liste dans un fichier CSV. J'ai tout fonctionné jusqu'au point où je veux écrire dans un fichier dans le flux de réponse. Cela ne fait rien.

Voici mon code:

Appelez la méthode à partir de la page.

$('#btn_export').click(function () {
         $.post('NewsLetter/Export');
});

Le code dans le contrôleur est le suivant:

[HttpPost]
        public void Export()
        {
            try
            {
                var filter = Session[FilterSessionKey] != null ? Session[FilterSessionKey] as SubscriberFilter : new SubscriberFilter();

                var predicate = _subscriberService.BuildPredicate(filter);
                var compiledPredicate = predicate.Compile();
                var filterRecords = _subscriberService.GetSubscribersInGroup().Where(x => !x.IsDeleted).AsEnumerable().Where(compiledPredicate).GroupBy(s => s.Subscriber.EmailAddress).OrderBy(x => x.Key);

                ExportAsCSV(filterRecords);
            }
            catch (Exception exception)
            {
                Logger.WriteLog(LogLevel.Error, exception);
            }
        }

        private void ExportAsCSV(IEnumerable<IGrouping<String, SubscriberInGroup>> filterRecords)
        {
            var sw = new StringWriter();
            //write the header
            sw.WriteLine(String.Format("{0},{1},{2},{3}", CMSMessages.EmailAddress, CMSMessages.Gender, CMSMessages.FirstName, CMSMessages.LastName));

            //write every subscriber to the file
            var resourceManager = new ResourceManager(typeof(CMSMessages));
            foreach (var record in filterRecords.Select(x => x.First().Subscriber))
            {
                sw.WriteLine(String.Format("{0},{1},{2},{3}", record.EmailAddress, record.Gender.HasValue ? resourceManager.GetString(record.Gender.ToString()) : "", record.FirstName, record.LastName));
            }

            Response.Clear();
            Response.AddHeader("Content-Disposition", "attachment; filename=adressenbestand.csv");
            Response.ContentType = "text/csv";
            Response.Write(sw);
            Response.End();
        }

Mais après que Response.Write(sw)rien ne se passe. Est-il même possible d'enregistrer un fichier de cette façon?

Cordialement

Modifier
Les en-têtes de réponse que je vois lorsque je clique sur le bouton sont:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/csv; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 2.0
Content-Disposition: attachment; filename=adressenbestand.csv
X-Powered-By: ASP.NET
Date: Wed, 12 Jan 2011 13:05:42 GMT
Content-Length: 113

Ce qui me semble correct.

Edit
Je me suis débarrassé de la partie jQuery et l'ai remplacée par un lien hypertexte et cela fonctionne très bien pour moi maintenant:

<a class="export" href="NewsLetter/Export">exporteren</a>
Gérard
la source
1
Peut-être que cette question sur SO aide: stackoverflow.com/questions/4522590/…
Rob
Pourriez-vous documenter votre réponse comme une réponse réelle plutôt que de modifier la question s'il vous plaît.
Caltor

Réponses:

250

yan.kun était sur la bonne voie mais c'est beaucoup plus facile.

    public FileContentResult DownloadCSV()
    {
        string csv = "Charlie, Chaplin, Chuckles";
        return File(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv", "Report123.csv");
    }
Biff MaGriff
la source
Comment gérerions-nous les chaînes contenant des virgules? J'ai essayé d'utiliser des guillemets doubles comme qualificatifs de texte, mais cela ne semble pas fonctionner.
Mike Cole
1
@mmssaann C'est la beauté, vous n'utilisez pas de javascript. Vous venez de définir le href de votre balise d'ancrage sur l'action. <a href="ControllerName/ActionName">Download CSV</a>
Biff MaGriff
1
J'ai défini le href pour la balise d'ancrage. Cela fonctionne bien. Cependant, je peux toujours voir la page entière est postée. existe-t-il un moyen de restreindre la publication?
mmssaann
1
@mmssaann Vous devriez poser une nouvelle question avec des détails sur votre configuration particulière.
Biff MaGriff
1
J'utilise votre façon de créer un fichier CSV de téléchargement, tout semble correct, je débogue, cela va au contrôleur. Mais le navigateur ne montre aucun signe de téléchargement de fichier? Pensez-vous que ce qui se passe, j'ai besoin de changer Web.config ou quelque chose?
zquanghoangz
13

Avec MVC, vous pouvez simplement renvoyer un fichier comme celui-ci:

public ActionResult ExportData()
{
    System.IO.FileInfo exportFile = //create your ExportFile
    return File(exportFile.FullName, "text/csv", string.Format("Export-{0}.csv", DateTime.Now.ToString("yyyyMMdd-HHmmss")));
}
yan.kun
la source
8
Voulez-vous vraiment créer un tas de fichiers sur le serveur Web? Et les nettoyer? Et la sécurité?
chris
@chris cela ne crée-t-il pas des fichiers dans la mémoire du serveur plutôt que dans le système de fichiers?
galdin
J'utilise votre façon de créer un fichier CSV de téléchargement, tout semble correct, je débogue, cela va au contrôleur. Mais le navigateur ne montre aucun signe de téléchargement de fichier? Pensez-vous que ce qui se passe, j'ai besoin de changer Web.config ou quelque chose comme ça?
zquanghoangz
7

En plus de la réponse de Biff MaGriff. Pour exporter le fichier à l'aide de JQuery, redirigez l'utilisateur vers une nouvelle page.

$('#btn_export').click(function () {
    window.location.href = 'NewsLetter/Export';
});
Harminder
la source
5

Que se passe-t-il si vous vous débarrassez du stringwriter:

        Response.Clear();
        Response.AddHeader("Content-Disposition", "attachment; filename=adressenbestand.csv");
        Response.ContentType = "text/csv";
        //write the header
        Response.Write(String.Format("{0},{1},{2},{3}", CMSMessages.EmailAddress, CMSMessages.Gender, CMSMessages.FirstName, CMSMessages.LastName));

        //write every subscriber to the file
        var resourceManager = new ResourceManager(typeof(CMSMessages));
        foreach (var record in filterRecords.Select(x => x.First().Subscriber))
        {
            Response.Write(String.Format("{0},{1},{2},{3}", record.EmailAddress, record.Gender.HasValue ? resourceManager.GetString(record.Gender.ToString()) : "", record.FirstName, record.LastName));
        }

        Response.End();
Chris
la source
non, cela ne fait aucune différence non plus. Je l'ai déjà résolu d'une manière différente. Voir ma modification. Merci pour votre aide quand même!
Gerard
3

En ce qui concerne Biff, voici quelques modifications qui me permettent d'utiliser la méthode pour faire rebondir CSV de jQuery / Post contre le serveur et revenir en tant qu'invite CSV à l'utilisateur.

    [Themed(false)]
    public FileContentResult DownloadCSV()
    {

        var csvStringData = new StreamReader(Request.InputStream).ReadToEnd();

        csvStringData = Uri.UnescapeDataString(csvStringData.Replace("mydata=", ""));

        return File(new System.Text.UTF8Encoding().GetBytes(csvStringData), "text/csv", "report.csv");
    }

Vous aurez besoin de la ligne unescape si vous appuyez dessus à partir d'un formulaire avec un code comme celui-ci,

    var input = $("<input>").attr("type", "hidden").attr("name", "mydata").val(data);
    $('#downloadForm').append($(input));
    $("#downloadForm").submit();
MonsCamus
la source
3

À partir d'un bouton dans la vue, appelez .click (appelez un script java). À partir de là, appelez la méthode du contrôleur par window.location.href = 'Controller / Method';

Dans le contrôleur, effectuez l'appel de base de données et récupérez la table de données ou appelez une méthode pour obtenir les données de la table de base de données vers une table de données, puis procédez comme suit,

using (DataTable dt = new DataTable())
                        {
                            sda.Fill(dt);
                            //Build the CSV file data as a Comma separated string.
                            string csv = string.Empty;
                            foreach (DataColumn column in dt.Columns)
                            {
                                //Add the Header row for CSV file.
                                csv += column.ColumnName + ',';
                            }
                            //Add new line.
                            csv += "\r\n";
                            foreach (DataRow row in dt.Rows)
                            {
                                foreach (DataColumn column in dt.Columns)
                                {
                                    //Add the Data rows.
                                    csv += row[column.ColumnName].ToString().Replace(",", ";") + ',';
                                }
                                //Add new line.
                                csv += "\r\n";
                             }
                             //Download the CSV file.
                             Response.Clear();
                             Response.Buffer = true;
                             Response.AddHeader("content-disposition", "attachment;filename=SqlExport"+DateTime.Now+".csv");
                             Response.Charset = "";
                             //Response.ContentType = "application/text";
                             Response.ContentType = "application/x-msexcel";
                             Response.Output.Write(csv);
                             Response.Flush();
                             Response.End();
                           }
Ashrughna
la source
1

Même si vous avez résolu votre problème, en voici un autre, essayez d'exporter csv à l'aide de mvc.

return new FileStreamResult(fileStream, "text/csv") { FileDownloadName = fileDownloadName };
Sandip
la source
0

Je pense que tu as oublié d'utiliser

  Response.Flush();

sous

  Response.Write(sw);

Vérifiez s'il vous plaît

Deepan Raj
la source
-3

Création de fichier Excel simple dans mvc 4

public ActionResult results () {return File (nouveau System.Text.UTF8Encoding (). GetBytes ("string data"), "application / csv", "filename.csv"); }

suresh B
la source
Ce n'est pas une bonne réponse. Veuillez vous référer à Comment rédiger une bonne réponse?
Clijsters
C'est une bonne réponse. Il est simplement mal formaté et reproduit la meilleure réponse publiée 6 ans plus tôt. : D
Caltor