Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download server generated CSV with ASP .NET MVC and jQuery AJAX request

I am working on mechanism to export data in CSV format. I am sending data in JSON format using jQuery :

var data = JSON.stringify(dataToSend);
 $.post('DumpToCSV', { 'data': data });

Then in the controller I am generating a CSV file :

 public ActionResult  DumpToCSV(string data)
    {
        Response.Clear();

        XmlNode xml = JsonConvert.DeserializeXmlNode("{records:{record:" + data + "}}");

        XmlDocument xmldoc = new XmlDocument();
        //Create XmlDoc Object
        xmldoc.LoadXml(xml.InnerXml);
        //Create XML Steam 
        var xmlReader = new XmlNodeReader(xmldoc);
        DataSet dataSet = new DataSet();
        //Load Dataset with Xml
        dataSet.ReadXml(xmlReader);
        //return single table inside of dataset
        var csv = CustomReportBusinessModel.ToCSV(dataSet.Tables[0], ",");

        HttpContext context = System.Web.HttpContext.Current;
        context.Response.Write(csv);
        context.Response.ContentType = "text/csv";
        context.Response.AddHeader("Content-Disposition", "attachment;filename=Custom Report.csv");
        Response.End();
        return null;
    }

It returns back the CSV in response, but how do I tell the browser to donwload it?

The difference between this topic : Returning a file to View/Download in ASP.NET MVC Is that I'm using AJAX request

like image 858
Vitalii Kalinin Avatar asked Mar 11 '15 18:03

Vitalii Kalinin


1 Answers

If you want to download file based on some data that you can post to Controller it's better not use Ajax, becouse it's really hard to deal with files via Ajax. One of posible solutions is to add link to additional library.

What i whould like to advice you is to use simple GET request:

In your javaScript code:

var urlParams = $.param(dataToSend);
window.location.href = "DumpToCSV"+ urlParams;

This way you serialize all your data to url string and have no problem with getting file via Ajax.

Then in your Controller it's better to return FileContentResult or even FileStreamResult if you have really big files. Also, your model that go into yout controller can be strongly typed and MVC ModelBuilder Map it from url string easily. So yout data object can be c# class like this:

public class CSVData
{
   public string Name { get; set; }
   public int Count { get; set; }
   public int SomeId { get; set; }
}

And you don't need to desirialize your data in Controller at all. See more info here.

public FileContentResult DumpToCSV(CSVData data)
{
    XmlNode xml = data.ToXmlNode();

    XmlDocument xmldoc = new XmlDocument();
    //Create XmlDoc Object
    xmldoc.LoadXml(xml.InnerXml);
    //Create XML Steam 
    var xmlReader = new XmlNodeReader(xmldoc);
    DataSet dataSet = new DataSet();
    //Load Dataset with Xml
    dataSet.ReadXml(xmlReader);
    //return single table inside of dataset
    var csv = CustomReportBusinessModel.ToCSV(dataSet.Tables[0], ",");

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

As you can see the is no need to work with HttpContext in MVC in your case you can do it much cleanier and obvious way.

PS. If your csv object is just a byte[] then you can write like this:

    return File(csv, "text/csv", "Custom Report.csv");
like image 94
teo van kot Avatar answered Nov 14 '22 01:11

teo van kot