What am I doing wrong here?
I am trying to export a list of customers to a downloadable csv file, that can be viewed in Excel
Currently I do not care about buttons and listeners, I just want to generate the actual csv file.
public class CSVExporter
{
public static void WriteToCSV(List<CustomerInformation> customerList)
{
string attachment = "attachment; filename=CustomerList.csv";
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "text/csv";
HttpContext.Current.Response.AddHeader("Pragma", "public");
WriteColumnName();
foreach (CustomerInformation customer in customerList)
{
WriteUserInfo(customer);
}
HttpContext.Current.Response.End();
}
private static void WriteUserInfo(CustomerInformation customer)
{
StringBuilder stringBuilder = new StringBuilder();
AddComma(customer.name, stringBuilder);
AddComma(customer.email, stringBuilder);
AddComma(customer.username, stringBuilder);
AddComma(customer.mobilenumber, stringBuilder);
AddComma(customer.dateCreated, stringBuilder);
AddComma(customer.birthday, stringBuilder);
HttpContext.Current.Response.Write(stringBuilder.ToString());
HttpContext.Current.Response.Write(Environment.NewLine);
}
private static void AddComma(string value, StringBuilder stringBuilder)
{
stringBuilder.Append(value.Replace(',', ' '));
stringBuilder.Append(", ");
}
private static void WriteColumnName()
{
string columnNames = "Name, Email, Username, Mobile number, Date created, Birthdate";
HttpContext.Current.Response.Write(columnNames);
HttpContext.Current.Response.Write(Environment.NewLine);
}
}
When I run the code, I get this:
I've simply used this
public HttpResponseMessage DownloadCsv()
{
const string csv = "mobile,type,amount\r\n123456789,0,200\r\n56987459,0,200";
var result = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StringContent(csv)};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Sample.csv"
};
return result;
}
Related
I've been reading through:
https://www.aspsnippets.com/Articles/Export-data-from-SQL-Server-to-CSV-file-in-ASPNet-using-C-and-VBNet.aspx
Rather than only have the option to download as csv as described there in:
//Download the CSV file.
Response.Clear();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment;filename=SqlExport.csv");
Response.Charset = "";
Response.ContentType = "application/text";
Response.Output.Write(csv);
Response.Flush();
Response.End();
is there a way using native asp.net to first zip the csv output from the csv variable in Response.Output.Write(csv); so that the user downloads SqlExport.zip rather than SqlExport.csv?
Roughly based on this, you can create a zip file while streaming it to the client;
Response.ContentType = "application/octet-stream";
Response.Headers.Add("Content-Disposition", "attachment; filename=\"SqlExport.zip\"");
using var archive = new ZipArchive(Response.Body, ZipArchiveMode.Create);
var entry = archive.CreateEntry("SqlExport.csv");
using var entryStream = entry.Open();
entryStream.Write(csv); // write the actual content here
entryStream.Flush();
Though rather than appending to a single csv string, you should probably consider using a StreamWriter to write each snippet of text directly into the response stream. Substituting from your linked csv example;
using var sw = new StreamWriter(entryStream);
// TODO write header
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn column in dt.Columns)
{
//Add the Data rows.
await sw.WriteAsync(row[column.ColumnName].ToString().Replace(",", ";") + ',');
}
//Add new line.
await sw.WriteLineAsync();
}
Though that is a terrible example of a csv file. Rather than substituting ';' characters, the string should be quoted & all quotes escaped.
However Response.Body is only available in .net 5 / core. To write directly to a http response in .net 4.8 or earlier, you'll have to write your own HttpContent. Putting everything together, including a better csv formatter;
public class ZipContent : HttpContent
{
private DataTable dt;
private string name;
public ZipContent(DataTable dt, string name = null)
{
this.dt = dt;
this.name = name ?? dt.TableName;
Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = $"{name}.zip"
};
}
private string formatCsvValue(string value)
{
if (value == null)
return "";
if (value.Contains('"') || value.Contains(',') || value.Contains('\r') || value.Contains('\n'))
return $"\"{value.Replace("\"", "\"\"")}\"";
return value;
}
private IEnumerable<DataColumn> Columns()
{
// Why is this not already an IEnumerable<DataColumn>?
foreach (DataColumn col in dt.Columns)
yield return col;
}
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
using var archive = new ZipArchive(stream, ZipArchiveMode.Create);
var entry = archive.CreateEntry($"{name}.csv");
using var entryStream = entry.Open();
using var sw = new StreamWriter(entryStream);
await sw.WriteLineAsync(
string.Join(",",
Columns()
.Select(c => formatCsvValue(c.ColumnName))
));
foreach (DataRow row in dt.Rows)
{
await sw.WriteLineAsync(
string.Join(",",
row.ItemArray
.Select(o => formatCsvValue(o?.ToString()))
));
}
}
protected override bool TryComputeLength(out long length)
{
length = 0;
return false;
}
}
Have a look at the ZipArchive Class
you can use public System.IO.Compression.ZipArchiveEntry CreateEntry (string entryName); to create an ZipEntry nd add it to an archive
I'm trying to export data as a CSV file in C#, but the problems starts when i'm trying to import the csv file in excel.
In excel I'm using the function "import from text", and afterwards I set the delimiter to semicolon
My problem is that some of the columns have linebreaks and then the import in excel is wrong.
I have tried with single and doubles quotes with no luck.
I have searched for a solution, but has not found one yet.
Anyone knows if lumenworks has a export function, because i'm using this for the import function
The problem is the export function and the linebreaks are required.
if (list.Any())
{
result = list.Select(i => new
{
i.Product.ProductIdentifier,
i.Product.Header,
body = string.Format("\"" + "{0}" + "\"", i.Product.Body),
Active = i.Product.Active ? 1 : 0,
Approved = i.Product.Approved ? 1 : 0,
i.Product.Sort,
i.Product.MetaDescription,
i.Product.MetaKeywords,
i.CatalogMenuItemContentItemId
}).ToList().ToCsv(";");
}
string attachment = "attachment; filename=myfile.csv";
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "text/csv";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("ISO-8859-1");
HttpContext.Current.Response.Write(result);
HttpContext.Current.Response.End();
public static string ToCsv<T>(this IEnumerable<T> items, string seperator = ",")
where T : class
{
var csvBuilder = new StringBuilder();
var properties = typeof(T).GetProperties();
foreach (T item in items)
{
string line = string.Join(seperator, properties.Select(p => p.GetValue(item, null).ToCsvValue()).ToArray());
csvBuilder.AppendLine(line);
}
return csvBuilder.ToString();
}
private static string ToCsvValue<T>(this T item)
{
return string.Format("{0}", HttpUtility.HtmlDecode(item.ToString()));
}
Any idea ?
I am exporting a CSV file from an ASP .NET page but somehow it contains HTML code and the data that are supposed to be exported (ie. 29 rows) are not complete (ie from supposedly 29 rows, only 17 shows up, and then HTML all the way down).
Here are my codes:
private void WriteToCSV()
{
var clientId = int.Parse(ddlClients.SelectedValue);
var taskTypeId = int.Parse(ddlTaskType.SelectedValue);
var mtComponent = new MainTableComponent();
var data = mtComponent.GetMainTableRecords(clientId, 0, taskTypeId);
if (data == null || data.Count == 0)
{
ShowAlertMessage("No available data to export.");
return;
}
var callerId = GetClientList().FirstOrDefault(x => x.ClientId == clientId).CallerId;
string attachment = string.Concat("attachment; filename=CallList_", ddlClients.SelectedItem.Text,
"_", ddlTaskType.SelectedItem.Text, "_", DateTime.Now.ToString("yyyyMMdd"), ".csv");
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "text/csv";
HttpContext.Current.Response.AddHeader("Pragma", "public");
HttpContext.Current.Response.Write("row,phone1,phone2,phone3,caller_id");
foreach (var d in data)
WriteUserInfo(d, callerId);
HttpContext.Current.Response.End();
}
private void WriteUserInfo(MainTableEntity person, string callerId)
{
HttpContext.Current.Response.Write(Environment.NewLine);
StringBuilder stringBuilder = new StringBuilder();
AddComma(person.RowNumber.ToString(), stringBuilder);
AddComma(FormatNumber(person.MobileNumber), stringBuilder);
AddComma("", stringBuilder);
AddComma("", stringBuilder);
AddComma(callerId, stringBuilder);
stringBuilder.Remove(stringBuilder.Length - 1, 1);
HttpContext.Current.Response.Write(stringBuilder.ToString());
}
private void AddComma(string value, StringBuilder stringBuilder)
{
value.Replace(",", "");
stringBuilder.Append(value).Append(",");
}
private string FormatNumber(string number)
{
if (string.IsNullOrWhiteSpace(number))
return null;
string n = number.Replace('-', ' ').Replace(" ", "").Trim();
return n;
}
The funny thing is, this does not happen on my local machine and on our test environment. It only happens in our production environment.
Any help is appreciated. Thank you very much!
I am exporting a csv file with the following code from a datatable. however names with accents are not exported correctly
http://screencast.com/t/i9N2mB34DL
var dt=JobContext.GetEngagementLetterReport(SPContext.Current.Site, int.Parse(rdlOption.SelectedValue));
var columnNames = new List<string>
{
Constants.SearchFields.Client.ClientCode,
Constants.SearchFields.Client.ClientName,
Constants.SearchFields.Job.JobCode,
Constants.SearchFields.Job.JobName,
Constants.SearchFields.Job.JobPartner,
Constants.SearchFields.Job.JobDirector,
Constants.SearchFields.Job.JobManager,
Constants.SearchFields.Job.BillContact,
Constants.SearchFields.Job.LineOfService,
Constants.SearchFields.Job.BusinessUnit,
Constants.SearchFields.Job.OperatingUnit,
"JobSiteUrl",
"FileNameUrl"
};
ExcelHelper.ExportDatatabletoExcel(dt, columnNames);
public static void ExportDatatabletoExcel(DataTable dt, List<string> columnNames)
{
try
{
const string attachment = "attachment; filename=elreport.csv";
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
string tab = "";
foreach (DataColumn dc in dt.Columns)
{
if (!columnNames.Contains(dc.ColumnName)) continue;
HttpContext.Current.Response.Write(tab + dc.ColumnName);
tab = ";";
}
HttpContext.Current.Response.Write("\n");
int i;
foreach (DataRow dr in dt.Rows)
{
tab = "";
for (i = 0; i < dt.Columns.Count; i++)
{
if(!columnNames.Contains(dt.Columns[i].ColumnName)) continue;
HttpContext.Current.Response.Write(tab + dr[i].ToString());
tab = ";";
}
HttpContext.Current.Response.Write("\n");
}
HttpContext.Current.Response.End();
}
catch (Exception ex)
{
string errorMessage = String.Format("ExportToExcelError: {0}", ex.Message);
LoggingService.LogError(LoggingCategory.General, ex, errorMessage);
throw;
}
}
Try adding the following after setting the content type.
// This is the missing part from your original code to set the charset and encoding - if this does not work, replace it with appropriate value, eg
Response.Charset = "utf-8";
Response.ContentEncoding = Encoding.UTF8;
// You might want to use this content type or experiment with appropriate MIME type
Response.ContentType = "text/csv";
TQ.
I need to export a really large csv file(~100MB). On the internet I found a similar code and implemented it for my case:
public class CSVExporter
{
public static void WriteToCSV(List<Person> personList)
{
string attachment = "attachment; filename=PersonList.csv";
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "text/csv";
HttpContext.Current.Response.AddHeader("Pragma", "public");
WriteColumnName();
foreach (Person person in personList)
{
WriteUserInfo(person);
}
HttpContext.Current.Response.End();
}
private static void WriteUserInfo(Person person)
{
StringBuilder stringBuilder = new StringBuilder();
AddComma(person.Name, stringBuilder);
AddComma(person.Family, stringBuilder);
AddComma(person.Age.ToString(), stringBuilder);
AddComma(string.Format("{0:C2}", person.Salary), stringBuilder);
HttpContext.Current.Response.Write(stringBuilder.ToString());
HttpContext.Current.Response.Write(Environment.NewLine);
}
private static void AddComma(string value, StringBuilder stringBuilder)
{
stringBuilder.Append(value.Replace(',', ' '));
stringBuilder.Append(", ");
}
private static void WriteColumnName()
{
string columnNames = "Name, Family, Age, Salary";
HttpContext.Current.Response.Write(columnNames);
HttpContext.Current.Response.Write(Environment.NewLine);
}
}
The problem is I want to start the download before(!) the whole CSV is constructed. Why is not it working like I suppose it too and what must I change?
You could probably force the response to be flushed to the client by using
Response.Flush();
after each record is appended to the stream. Please refer to this article for more details:
http://support.microsoft.com/kb/812406