Excel File opening in browser not calling Excel - c#

I am calling a function to return an Excel file and it is not opening in Excel, instead it is opening another tab in the browser. Here is my view:
#model InventoryControl.Models.AdminModel
<div>
#if (Model.TableCounts != null)
{
<table class="table_body">
<tr>
<th>#Html.DisplayNameFor(x=>x.TableCountModel.TableName)</th>
<th>#Html.DisplayNameFor(x=>x.TableCountModel.Rows)</th>
<th>#Html.DisplayNameFor(x=>x.TableCountModel.Count)</th>
<th>#Html.DisplayNameFor(x=>x.TableCountModel.Size)</th>
</tr>
#foreach (var item in Model.TableCounts)
{
<tr>
<td>
#item.TableName
</td>
<td>
#item.Rows
</td>
<td>
#item.Count
</td>
<td>
#item.Size
</td>
</tr>
}
</table>
}
else
{
<p><i>No data available</i></p>
}
</div>
<div>
#Html.ActionLink("Excel", "Excel")
</div>
Here is my controller function:
public void Excel()
{
var grid = new System.Web.UI.WebControls.GridView();
grid.DataSource = ReportsRepository.TableCounts();
grid.DataBind();
Response.ClearContent();
Response.AddHeader("Content-Dispositon", "attachment; filename=TableCounts.csv");
Response.ContentType = "text/csv";
Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
grid.RenderControl(htw);
Response.Write(sw.ToString());
Response.End();
}
I have looked in vain for an example that works and cannot find something that does.
If I make this change:
Response.AddHeader("Content-Dispositon", "attachment; filename=TableCounts.xlsx");
Response.ContentType = "application/vnd.ms-excel";
The file save/open dialog is fired but it says it is Excel 2003 format and the filename it says is "Excel".

Your code doesn't create an Excel file, it creates a CSV file. The content type isn't Excel-specific either. A browser may decide that Excel is the appropriate application to open this text file or not.
Even if the browser selects Excel, opening the file may fail, eg if the client's locale uses , as a decimal separator. This is common in European countries. In this case Excel expect ; as the field separator and may open the CSV as a single text block.
Instead of trying to trick the browser into opening a CSV in Excel, create a real Excel file using a library like EPPlus. EPPlus is available as a Nuget package so it's very easy to add it to your project.
The library's documentation contains an article on how to use it in Web applications. Once you remove the formatting code from the example, the code is very simple:
private void DumpExcel(DataTable tbl)
{
using (ExcelPackage pck = new ExcelPackage())
{
//Create the worksheet
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Demo");
//Load the datatable into the sheet, starting from cell A1. Print the column names on row 1
ws.Cells["A1"].LoadFromDataTable(tbl, true);
//Write it back to the client
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=ExcelDemo.xlsx");
Response.BinaryWrite(pck.GetAsByteArray());
}
}
Excel files are compressed which means that sending the file to the client will be a lot faster, especially for large files

Check your default program for opening csv files and set it to Excel.

Related

Generate and Save file to database

I have a record set (DataTable) that I am saving to Excel and then need to save to a database (as binary).
I have two parts working separately, but I can't figure out how to tie them both together without having to actually save a hard copy of the Excel to the disk.
Here is the "export to Excel" code:
string attachment = "attachment; filename=" + filename;
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/ms-excel";
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
gvCompleteCases.RenderControl(htw);
Response.Write(sw.ToString());
Response.End();
and the "save file to database" snippet:
byte[] fileData = null;
using (var binaryReader = new BinaryReader(file.InputStream))
{
fileData = binaryReader.ReadBytes(file.ContentLength);
UploadFile.Upload2(GetD(), file.ContentLength, fu.FileBytes, numberOfPages);
}
The above example saves the file to user's machine and then I have to point to its location to save to the database, is there a way I can create the Excel file, without saving to user's hard disk, before saving it to the database?
I guess what I'm asking is how do I get the fileData of the created Excel, without saving it to the computer?

mso-data-placement:same-cell not working

I am exporting data into Excel from a web page. This should be a no brainer, but there are <p> tags in the data. This causes Excel to create new rows when the data should all be in the same cell. After some research I found that mso-data-placement should do the trick, but it's not working. Excel opens, the data is displayed, but extra uncessary rows are created. Here is the code I use to export the data:
protected void doexcel()
{
string style = #"<style type='text/css'>P {mso-data-placement:same-cell; font-weight:bold;}</style>";
HttpResponse response = HttpContext.Current.Response;
// first let's clean up the response.object
response.Clear();
response.Charset = "";
//set the response mime type for excel
response.ContentType = "application/vnd.ms-excel";
Random RandomClass = new Random();
int RandomNumber = RandomClass.Next();
String filename = "a" + RandomNumber + DateTime.Now + ".xls";
response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"" );
// create a string writer
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
HttpContext.Current.Response.Write(style);
SqlDataSourceEmployeeAssets.ConnectionString = MyObjects.Application.CurrentContext.ConnectionString;
String sql = (string)Session["sql"];
SqlDataSourceEmployeeAssets.SelectCommand = sql;
// lCount.Text = "Query returned " + getCount(query) + " rows.";
DataGrid dge = new DataGrid();
dge.DataSource = SqlDataSourceEmployeeAssets;
dge.DataBind();
dge.RenderControl(htw);
response.Write(sw.ToString());
response.End();
}
}
}
This is an example of the raw data in the database that is giving me grief:
<P>4/13/2011 : Cheng "Jonathan" Vaing is with BSES Graffiti Unit.</P><P>4/13/2011 : Cheng "Jonathan" Vaing is with</P>
Suggestions?
I tried a couple of other things
I went straight to the data and added the mso-data-placement attribute to the paragraph tag inline. Still didn't work. The data looked like this
<P style="mso-data-placement:same-cell> my data </p>
I tried other mso-* attributes, that didn't work either. For example, I changed my stylesheet to look like this
<style type='text/css'>P {mso-highlight:yellow}</style>";
Why oh why doesn't Excel recognize my mso-* attributes?!?!
There is a solution but it is not clean.
After the dge.DataBind, place the following code. This will encode the text of each cell
foreach (DataGridItem dgi in dge.Items)
{
foreach (TableCell cell in dgi.Cells)
{
cell.Text = WebUtility.HtmlEncode(cell.Text);;
}
}
The Excel file, when opened, should show the raw data with the markup, all in one cell.
I found that this works because Excel actually encodes the text, as well. To see what Excel does in action, do the following:
Create a new workbook in Excel (I am using Office 2013).
In the first cell, paste the raw data (as you have it displayed). Do this by first pressing F2 (insert into cell), then paste the text.
Save the workbook as an HTML file (or web page).
Using windows explorer, go to the folder location of where you saved the file. There should be a hidden folder (i think it is hidden) with the same name as your file. For example, if your workbook is Book1.htm, there should be a folder labeled Book1_files.
In this folder, there should be an HTM file with the name sheet001.htm. Open this file in notepad (or any text editor...not excel or word)
Locate your raw data. You will see that the text is not showing the HTML markup, rather it is showing the encoded version.
Hope this helps.

Stop Date Auto-Format when Exporting from DataGrid to Excel in C#

I am currently formatting a Date for a specific Excel file Export from a DataSet/DataGrid.
The Date is formatted like so:
DateTime date = Convert.ToDateTime(entry.Date);
string formatdate = String.Format("{0:yyyy/MM/dd}", date);
Once creating the DataSet is said and done, I use the following code to Export the DataSet to an Excel file:
public static void ExportDStoExcel(DataSet ds, string filename)
{
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.Charset = "";
response.ContentType = "application/vnd.ms-excel";
response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
DataGrid dg = new DataGrid();
dg.DataSource = ds.Tables[0];
dg.DataBind();
dg.RenderControl(htw);
response.Write(sw.ToString());
response.End();
}
}
}
My only problem is once I export this to Excel, Excel Auto-Formats the Dates like this: MM/DD/YYYY instead of YYYY/MM/DD.
I understand this could be achieved manually by opening in Excel, but the Export is being built into an Automated System and needs to be hard coded.
Is there any way of bypassing Excel's DateTime Auto-Formatting?
I had the same issue and solved it by adding a non breaking space (&nbsp) in front of the text. Stopped Excel from auto-formatting. Not the cleanest solution but did the trick for me...
Right now you are just outputting HTML table, that Excel interprets how it likes. You'd have bring yourself down to Excel's level to be able to specify column's properties (set type to Text instead of General).
This means that you need to generate actual xls file (there are various libraries out there for that). Or (if restriction to Office 2010 is acceptable) got with Open XML format which you can write with regular .NET API.
You can style excel cells with mso-number-format
mso-number-format:"\\#"
\# will tell excel to treat all data in text format only. So auto format won't happen.
Please update your code like this:
response.ContentType = "application/vnd.ms-excel";
response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
response.Write("<html xmlns:x=\"urn:schemas-microsoft-com:office:excel\">");
response.Write("<head><style> td {mso-number-format:\\#;} </style></head><body>");
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
DataGrid dg = new DataGrid();
dg.DataSource = ds.Tables[0];
dg.DataBind();
dg.RenderControl(htw);
response.Write(sw.ToString());
response.Write("</body></html>");
response.End();
}
}
OR
you can try with specific date format also.
Refer: http://cosicimiento.blogspot.in/2008/11/styling-excel-cells-with-mso-number.html
mso-number-format:"yyyy\/mm\/dd"

Download .xlsx file using Response.TransmitFile()

I'm working on some code that generates an Excel spreadsheet server-side and then downloads it to the user. I'm using ExcelPackage to generate the file.
The generation is working just fine. I can open the generated files using Excel 2007 with no issues. But, I'm having trouble downloading the file with Response.TransmitFile().
Right now, I have the following code:
//Generate the file using ExcelPackage
string fileName = generateExcelFile(dataList, "MyReportData");
Response.AddHeader("content-disposition", "attachment;filename=FileName.xls");
Response.ContentType = "application/vnd.xls"
Response.Charset = "";
Response.TransmitFile(fileName);
When Excel 2007 opens the file downloaded as above, it gives the "file format doesn't match extension" warning. After clicking past the warning, Excel displays the raw xml contents of the file.
If I change the file extension, like so
Response.AddHeader("content-disposition", "attachment;filename=FileName.xlsx");
Excel 2007 gives an "Excel found unreadable content in the file" error, followed by a dialog that offers to locate a converter on the web. If I click "no" on this dialog, Excel is able to load the data.
I've also experimented with different MIME types, like application/vnd.ms-excel and application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, combined with file extensions of .xls and .xlsx. All combinations result in one of the two behaviors mentioned above.
What is the correct combination of file extension and MIME type to use in this scenario? What else could cause this failure, other than an improper MIME type or extension?
FYI, this is occurring with Visual Studio's built-in development web server. I haven't yet tried this with IIS.
I can't definitely say that there's anything wrong with your approach, but I'll just share some observations from doing something similar.
Headers are Pascal Case, most browsers shouldn't care but I would change your content-disposition to Content-Disposition. Changing the Charset shouldn't be necessary or relevant. Your content type should be fine, I would only use application/vnd.openxmlformats-officedocument.spreadsheetml.sheet and .xlsx if that is actually the content of the file, otherwise stick with application/vnd.ms-excel and .xls.
Another thing you should consider is sending the browser the Content-Length:
Response.AddHeader("Content-Length", new System.IO.FileInfo("FileName.xlsx").Length);
Also have you tried this with multiple browsers? Just wondering if it's a vendor-specific problem.
As a last ditch effort, you can set your Content-Type to application/octet-stream, and any browser should offer to download it, and then most browsers will let you open it after it's downloaded based on the extension.
use this
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=\"filename + ".zip" + "\"");
Response.TransmitFile(zipPath);
Response.Flush();
Response.Close();
Response.End();
in your code is
Response.AddHeader("content-disposition", "attachment;filename=\FileName.xlsx\");
Try like this
public void DataTableToExcel(DataTable dt, string Filename)
{
MemoryStream ms = DataTableToExcelXlsx(dt, "Sheet1");
ms.WriteTo(HttpContext.Current.Response.OutputStream);
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + Filename);
HttpContext.Current.Response.StatusCode = 200;
HttpContext.Current.Response.End();
}
public static MemoryStream DataTableToExcelXlsx(DataTable table, string sheetName)
{
MemoryStream result = new MemoryStream();
ExcelPackage excelpack = new ExcelPackage();
ExcelWorksheet worksheet = excelpack.Workbook.Worksheets.Add(sheetName);
int col = 1;
int row = 1;
foreach (DataColumn column in table.Columns)
{
worksheet.Cells[row, col].Value = column.ColumnName.ToString();
col++;
}
col = 1;
row = 2;
foreach (DataRow rw in table.Rows)
{
foreach (DataColumn cl in table.Columns)
{
if (rw[cl.ColumnName] != DBNull.Value)
worksheet.Cells[row, col].Value = rw[cl.ColumnName].ToString();
col++;
}
row++;
col = 1;
}
excelpack.SaveAs(result);
return result;
}

Export HTML Table in asp.net MVC

I trying to export an HTML table named Table that is dynamically binded to ViewData.Model in C#. I have a method called export that is called based on another method's actions. so everything before that is set up.. I just don't know how to export the data to a CSV or Excel file.. So when the I step inside the Export method I don't know what next to do to export the table. Can someone help me
public void Export(List<data> List)
{
//the list is the rows that are checked and need to be exported
StringWriter sw = new StringWriter();
//I don't believe any of this syntax is right, but if they have Excel export to excel and if not export to csv "|" delimeted
for(int i=0; i<List.Count;i++)
{
sw.WriteLine(List[i].ID+ "|" + List[i].Date + "|" + List[i].Description);
}
Response.AddHeader("Content-Disposition", "attachment; filename=test.csv");
Response.ContentType = "application/ms-excel";
Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
Response.Write(sw);
Response.End();
}
I don't quite understand the whole "export an HTML table named Table that is dynamically binded to ViewData.Model" so I'll just ignore that and focus on your Export(List<data> list) method. Btw, you never really mentioned what was going wrong and where.
I see you had written "if they have Excel export to excel and if not export to csv" - I would personally just export it as a CSV file in both cases because excel can handle csv files no problem.
So with that in mind, here would be my export method based on your code.
public void Export(List<DataType> list)
{
StringWriter sw = new StringWriter();
//First line for column names
sw.WriteLine("\"ID\",\"Date\",\"Description\"");
foreach(DataType item in list)
{
sw.WriteLine(string.format("\"{0}\",\"{1}\",\"{2}\"",
item.ID,
item.Date,
item.Description));
}
Response.AddHeader("Content-Disposition", "attachment; filename=test.csv");
Response.ContentType = "text/csv";
Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
Response.Write(sw);
Response.End();
}
This is an excellent example, but I think that need a globalization modification.
String ltListSeparator = CultureInfo.CurrentUICulture.TextInfo.ListSeparator;
sw.WriteLine(string.format("{0}" + ltListSeparator + "{1}" + ltListSeparator + "{2}", item.ID, item.Date, item.Description));
I think your controller action method will need to wrap the data items in an html table which you may want to do any way you like, So your html+ data will be stored in a string and then you could do something like below- (its not exacly built for MVC but its easy to modify for it).
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/ms-excel";
Response.Write(yourDataAndHtmlAsString);
Response.End();
CSV is a simple format and can be built up easily as a string.
http://en.wikipedia.org/wiki/Comma-separated_values
You could create an excel spreadsheet of what you think the end product should look like, save as CSV, open it in notepad and try and replicate it using a string builder.

Categories