91

I am trying to export a list to a CSV file. I got it all working up to the point I want to write to file to the response stream. This doesn't do anything.

Here is my code:

Call the the method from the page.

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

The code in the controller is as follows:

[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(); } 

But after Response.Write(sw) nothing is happening. Is it even possible to save a file this way?

Regards

Edit
The response headers I see when I click the button are:

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 

Which seem OK to me..

Edit
I got rid of the jQuery part en replaced it by an hyperlink and this is working fine for me now:

<a class="export" href="NewsLetter/Export">exporteren</a> 
2
  • 1
    Maybe this question on SO helps: stackoverflow.com/questions/4522590/… Commented Jan 12, 2011 at 13:29
  • 1
    Could you document your answer as an actual answer rather than editing the question please. Commented Mar 10, 2020 at 11:22

8 Answers 8

261

yan.kun was on the right track but this is much much easier.

 public FileContentResult DownloadCSV() { string csv = "Charlie, Chaplin, Chuckles"; return File(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv", "Report123.csv"); } 
Sign up to request clarification or add additional context in comments.

9 Comments

How would we handle strings that contain commas? I tried using double quotes as text qualifiers but it doesn't seem to work.
@mmssaann That's the beauty of it, you don't use javascript. You just set the href of your anchor tag to the action. <a href="ControllerName/ActionName">Download CSV</a>
I have set the href for anchor tag. It is working fine. However the I can still see the entire page is posted back. is there a way to restrict the postback?
@mmssaann You should ask a new question with details about your particular setup.
I use your way to create download CSV, everything seems ok, I debug, it goes to the controller. But the browser doesn't show any sign of download file? Do you think what's happen, I need to change Web.config or something?
|
14

With MVC you can simply return a file like this:

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"))); } 

3 Comments

Do you really want to create a bunch of files on the web server? What about cleaning them up? What about security?
@chris doesn't that create files in the server's memory rather than the filesystem?
I use your way to create download CSV, everything seems ok, I debug, it goes to the controller. But the browser doesn't show any sign of download file? Do you think what's happen, I need to change Web.config or something?
7

In addition to Biff MaGriff's answer. To export the file using JQuery, redirect the user to a new page.

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

Comments

5

What happens if you get rid of the 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(); 

1 Comment

nope that doesn't make a difference either. I got it solved allready in a different way. See my edit. Thanks for your help anyway!
3

Respect to Biff, here's a few tweaks that let me use the method to bounce CSV from jQuery/Post against the server and come back as a CSV prompt to the user.

 [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"); } 

You'll need the unescape line if you are hitting this from a form with code like the following,

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

Comments

3

From a button in view call .click(call some java script). From there call controller method by window.location.href = 'Controller/Method';

In controller either do the database call and get the datatable or call some method get the data from database table to a datatable and then do following,

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(); } 

Comments

1

Even if you have resolved your issue, here is another one try to export csv using mvc.

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

Comments

0

I Think you have forgot to use

 Response.Flush(); 

under

 Response.Write(sw); 

please check

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.