C# Export to Excel xls - c#

I have a method that currently exports the results of a stored procedure to a CSV file. I've been tasked with altering it to export to XLS but I'm having some trouble.
The code:
protected void ExportFundingSummaryToExcelSA(Object sender, EventArgs e)
{
const string fileName = "METT Dashboard - Funding Summary";
const string rowFormat = "{0},{1},{2},{3},{4},{5}\n";
Response.Clear();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment;filename=" + fileName + ".csv");
Response.Charset = "";
Response.ContentType = "text/csv";
GetCompanyGroupCode();
var sb = new StringBuilder();
sb.AppendFormat(rowFormat, "Sector", "Product Line", "Program Number", "Program Description","Participating Companies", "Gross");
var customerId = CurrentUser.Company.Id;
var year = 2015;
// Set Title Row
Response.Write(year + " Products Lines for: " + CurrentUser.Company.Name + " (" + customerId + ")\n");
// Set Generated Date (Report Created on: 9/29/2004 3:33:32 PM)
Response.Write("Report Created on: " + System.DateTime.Now.ToString() + "\n\n\n");
var fundingData = GetFundingData();
if (fundingData != null)
{
if (fundingData.Summary != null && fundingData.Summary.Count > 0)
{
var summaries = MoveSetAsidesDown(fundingData.Summary);
for (var i = 0; i < summaries.Count; i++)
{
if (fundingData.Programs != null && fundingData.Programs.Count > 0)
{
foreach (var program in fundingData.Programs)
{
if (program.PlId == summaries[i].PlId)
{
sb.AppendFormat(rowFormat,
SharePointUtil.ToCsvFriendly(summaries[i].SectorName),
SharePointUtil.ToCsvFriendly(summaries[i].PlName),
SharePointUtil.ToCsvFriendly(program.TargetId.ToString()),
SharePointUtil.ToCsvFriendly(program.TargetName),
SharePointUtil.ToCsvFriendly(program.ParticipantsCount.ToString()),
SharePointUtil.ToCsvFriendly(program.AmountAllocated.ToString("$###,###,###,##0")));
}
}
}
}
}
}
Response.Write(sb.ToString());
Response.Flush();
Response.End();
}
The big catch is the data manipulation once the data comes back from GetFundingData, I have to do it like that because our DBA is out and I need to knock this out. I thought I'd be able to just change the content type but that blows it up. Any help would be appreciated.

I think the problem is your trying to use CSV formatting to create a XLS file. CSV uses a text based formatting with commas separating the data. XLS uses a binary style of formatting. Because XLS is a Microsoft file format, you will need to use Excel's Object Library to create the files. I do not know if you have the option, but if you can include EPPlus in your application, EPPlus can create, open, and edit XLSX files. XLSX is not XLS, but any version of Excel after the 2007 version can read both types.
[Edit]
Thank you Scott Chamberlain for pointing out that TrevorGoodchild is using a Sharepoint web service. As Scott Chamberlain has pointed out in his comment above, Open XML SDK is an option when using an IIS web service. In addition, because EPPlus does not use COM Interop it may also be usable in your application.

Related

Export Grid Data in a user control to excel on button click

I have a user control with a Grid. Now I have added an export to excel button on the Same user grid just above the grid to enable user to export the corresponding Grid's data to Excel. I wrote the following function on button click even t in User control.
protected void Home_ExportExcel_Click(object sender, EventArgs args)
{
DataTable resultTbl = new DataTable();
if (this.HomeGridDataSource != null)
resultTbl = this.HomeGridDataSource as DataTable;
Download(resultTbl, this.MasterPage.CurrentLibrary);
}
the Download Function is
private void Download(DataTable tb)
{
string attachment = "attachment; filename=HomeGridData" + DateTime.Now.ToString() + ".xls";
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/vnd.ms-excel";
string tab = "";
foreach (DataColumn dc in tb.Columns)
{
Response.Write(tab + dc.ColumnName);
tab = "\t";
}
Response.Write("\n");
int i;
foreach (DataRow dr in tb.Rows)
{
tab = "";
for (i = 0; i < tb.Columns.Count; i++)
{
Response.Write(tab + dr[i].ToString());
tab = "\t";
}
Response.Write("\n");
}
Response.End();
}
Now I get the response for the request as a text format but I need this to be downloaded to the user machine with the Grid data.
I also tried generating .xml file with the Excel styles etc.. but I get the Same result as a text format in response object but I am expecting it to be downloaded.
What am I missing here?
Setting up content type as Excel file is not enough for client to consider response as a Excel file. Your server responds by textual information that is treated by client as a common response. Even though user saves your response to Excel file, the file will not be compliant with the format because it is text.
The better way to work this out is to generate an Excel file using some library. For example., EPPlus.
Using that library you can generate an Excel file in memory (without creating a physical file on disk) and then return it as a stream using Response.OutputStream.Write. A good example of how to respond by stream\file is in the following topic.

How to convert table data to Excel format in an Entity Framework project?

I have an Entity Framework project, I have tables named
dbo.patient
dbo.doctor
dbo.disease
These three tables are interconnected.
I need to convert the patient data with doctor name and disease name into an Excel format file... what do I have to do to accomplish this?
I have no idea how to do it...
Can anyone provide steps?
Should I create a stored procedure? How to convert data to Excel format?
Can I do it without using a stored procedure?
You can use free and opensource library called EPPlus for that.
Here is the Link :
EPPlus-Create advanced Excel spreadsheets
Here is how to do that ..
Step 1 :
Run following command on the Package Manager console :
PM > install-package epplus
Step 2 :
This is the method for exporting data :
Note : You can replace the data with your actual data after retrieving it from the server by using EF query.
public void ExportListUsingEPPlus()
{
//this is the data retrieval point you have to replace with your data
var data = new[]{
new{ Name="Myname", Email="myna#google.com"},
new{ Name="yourname", Email="your#yahoo.com"},
new{ Name="saman", Email="saman#yahoo.com"},
};
ExcelPackage excel = new ExcelPackage();
var workSheet = excel.Workbook.Worksheets.Add("Sheet1");
workSheet.Cells[1, 1].LoadFromCollection(data, true);
using (var memoryStream = new MemoryStream())
{
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=Contact.xlsx");
excel.SaveAs(memoryStream);
memoryStream.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
}
}
You can export data in html or csv format and let Excel do the conversion. This has it's own pitfalls.
For example, with csv, if you have text data that looks like a date or a number, Excel will convert it to a date or a number. When this might happen, I put a tab character into the data to stop it.
And, with html, if you tell the browser that it should be opened using Excel, the user gets a warning that the format isn't Excel.
Nonetheless, I have used these techniques to do simple exports in my MVC application without resorting to a library.
To set the response to Excel (for html output):
protected void SetResponseToExcel(string fileName)
{
HttpContext.Response.Clear();
HttpContext.Response.AddHeader("content-disposition",
"attachment;filename=" + fileName);
HttpContext.Response.Charset = "";
HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Response.ContentType = "application/vnd.ms-excel";
}
To set the response to csv:
protected void SetResponseToText(string fileName)
{
HttpContext.Response.Clear();
HttpContext.Response.AddHeader("content-disposition",
"attachment;filename=" + fileName);
HttpContext.Response.Charset = "";
HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Response.ContentType = "text/csv";
}
To do the export:
public ActionResult MyExport()
{
SetResponseToText("MyFilename.csv");
Response.Write(String.Format("\"{0}\",...,{26}",
"Heading 1", ..., Environment.NewLine));
Response.Flush();
IEnumerable<MyClass> exportData = _MyService.GetMyData();
foreach (var row in exportData)
{
Response.Write(String.Format("\"{0}\"...,{26}",
"\t" + row.Field1, //tab character to force Excel to treat it as text
row.Field2, ..., Environment.NewLine));
}
Response.Flush();
Response.End();
return null;
}

Opening an excel file using asp.net C#

My requirement is to open an excel file which is under Attachment folder. So I took the reference from here and used abatishchev answer for my requirement. So I tried that in my below code.
public void ExportExcel()
{
string str_lwpc_query = string.Empty;
str_lwpc_query = "select company_name 'COMPANY NAME',Deputed_Company_Name 'DEPUTED COMPANY NAME',emp_card_no 'EMP CODE',emp_name 'EMPLOYEE NAME',LWP,'' Remarks, " +
"Adj_Days Gain_Loss_LOP_Days, VAL_DAY LOP_Days_Desc, month, year from XXACL_EMP_INFO_LWP_OTDAYS_HRS_V " +
"where emp_type='C' and month = '3' and year = '2015' ";
DataTable Dt_lwpc = new DataTable();
Dt_lwpc = CF.ExecuteDT(str_lwpc_query);
DataSet DS_lwpc = new DataSet();
DS_lwpc.Tables.Add(Dt_lwpc);
DS_lwpc.Tables[0].TableName = "Employee loss of pay for consultant Details";
var directory = Server.MapPath("~/Attachment/");
ExcelLibrary.DataSetHelper.CreateWorkbook(directory + "Employee_lwpc_Details.xls", DS_lwpc);
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
ExcelLibrary.Office.Excel.Workbook wb = excel.Workbooks.Open(ExcelLibrary.DataSetHelper.CreateWorkbook(directory + "Employee_lwpc_Details.xls", DS_lwpc));
}
but I get error in the last line as
The best overloaded method match for Microsoft.Office.Interop.Excel.Workbooks.Open(string, object, object, object, ...........) has some invalid arguments
kindly suggest what is wrong
If you want users of your website to open an excel file that you've created on server, than you don't need to open it there - just send it to the user. Replace the last two lines of code with this:
string filePath = directory + "Employee_lwpc_Details.xls";
Response.ContentType = "Application/vnd.ms-excel";
Response.AppendHeader("content-disposition",
"attachment; filename=" + "Employee_lwpc_Details.xls");
Response.TransmitFile(filePath);
Response.End();
Microsoft.Office.Interop.Excel.Workbooks.Open takes a filename and a number of additional parameters, see the MSDN documentation here. The CreateWorkbook method that you're calling is not returning the required arguments for Open.

Create ZIP File Then Send to Client

I have a button in my web page that will export CSV files. There are 5 files in total. When the client clicks the button, the server will create the files, compress them into one ZIP file, then send the ZIP file to the client for download.
I have heard around the forums about SharpZipLab and DotNetZip, but I haven't explored any yet. I have also heard using System.IO.Compression. Which of these methods would you recommend?
I have this code to create the 5 CSV files:
StringBuilder sb = new StringBuilder();
DataTable[] dtCSV =
{
file1BLO.SelectFile1ForCSV(),
file2BLO.SelectFile2ForCSV(),
file3BLO.SelectFile3ForCSV(),
file4BLO.SelectFile4ForCSV(),
file5BLO.SelectFile5ForCSV()
};
for (int i = 0; i <= 4; i++)
{
DataTable dt = dtCSV[i];
foreach (DataRow dr in dt.Rows)
{
string[] fields = dr.ItemArray.Select(field => field.ToString()).ToArray();
sb.AppendLine(string.Join("|", fields));
}
Response.ContentType = "application/text";
Response.AddHeader("content-disposition", "attachment;filename=CAPRES-FILE" +
(i + 1) + "-" + DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".txt");
Response.Output.Write(sb);
Response.Flush();
sb.Clear();
}
Response.End();
EDIT I'm using ASP.NET v4.0.
EDIT 2 Apparently I have System.IO.Compression, which is weird because I though it is only supported in v4.5. Coincidentally, I don't have System.IO.Packaging.
With the help of Sachu, we were able to accomplish this requirement. We used DotNetZip over SharpZipLib due to its licensing issues.
In facilitate our development of this functionality, I ought to create a program flow based on my requirements:
Create text files
Add the text files to a folder
Compress this folder in Zip format
Send to client using Response
Delete files
Step 0 - Setup Project
Before we start the process, we must prepare the project. This include adding necessary folders and instantiate variables.
First we add a folder to which we will 'temporarily' add the text files. This folder will also be the one that will get compressed. I decided to create the folder in the root directory of the project with the name CSV.
Now we'll be using the DotNetZip library. You can download it here. Add the library to your project references. Then add the using, which is using Ionic.Zip;.
Then we instantiate the variables such as the zipFileName, textFileName, etc. The names speak for themselves.
The data that I'll be using for the text files will be from the DataTable[] array, which each DataTable corresponding to a specific SQL query.
DataTable[] dtCSV =
{
file1BLO.SelectFile1ForCSV(),
file2BLO.SelectFile2ForCSV(),
file3BLO.SelectFile3ForCSV(),
file4BLO.SelectFile4ForCSV(),
file5BLO.SelectFile5ForCSV()
};
StringBuilder sb = new StringBuilder();
string textFileNameTemplate = Server.MapPath(#"~\CSV") + #"\file";
Response.Clear();
Response.BufferOutput = false;
Response.ContentType = "application/zip";
Response.AppendHeader("content-disposition", "attachment;filename=CAPRES-" +
DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".zip");
Step 1 - Create Text Files
This is fairly easy. I used a StringBuilder to convert the results from the DataTables. Using this, I then used a StreamWriter to build the text files themselves.
for (int i = 0; i <= 4; i++)
{
DataTable dt = dtCSV[i];
foreach (DataRow dr in dt.Rows)
{
string[] fields = dr.ItemArray.Select(field => field.ToString()).ToArray();
sb.AppendLine(string.Join("|", fields));
}
string textFileName = textFileNameTemplate + (i + 1) + ".txt";
var textFile = new StreamWriter(textFileName);
textFile.WriteLine(sb.ToString());
textFile.Flush();
textFile.Close();
}
Notice how I used the textFileNameTemplate variable. I append the iterator and a .txt file extension. Therefore, we will have files named file1.txt, file2.txt, file3.txt, etc.
Step 3 & 4 - Compress The Folder & Send To Client
Now we can proceed with the zipping. We modified the code in Step 2 to accommodate the library.
using (ZipFile zip = new ZipFile()) //encapsulate Step 2 code in this code block
{
for (int i = 0; i <= 4; i++)
{
DataTable dt = dtCSV[i];
foreach (DataRow dr in dt.Rows)
{
string[] fields = dr.ItemArray.Select(field => field.ToString()).ToArray();
sb.AppendLine(string.Join("|", fields));
}
string textFileName = textFileNameTemplate + (i + 1) + ".txt";
var textFile = new StreamWriter(textFileName);
textFile.WriteLine(sb.ToString());
textFile.Flush();
textFile.Close();
sb.Clear();
zip.AddFile(textFileName, #"\"); //this is new
}
zip.Save(Response.OutputStream); //this is also new
}
Response.Flush();
Response.End();
zip.AddFile(textFileName, #"\"); adds the text file to an archive. The #"\" means that DotNetZip will not create subfolders that lead to the file, e.g. if my file is in this path: C:\User\Documents\...\file1.txt, the archive would have a similar structure of folders. With #"\", the archive will only contain the text file.
Also take note of sb.Clear(); and its position in the code. It's important that it is inside the for loop but after the textFile.WriteLine(sb.ToString()); line. This makes sure that strings written before are cleared before looping again. This avoid carrying over strings from File1 to File2, and File2 to File3, and so on.
zip.Save(Response.OutputStream); will directly output the Zip file to the Response and does not save the file in the server.
Step 5 - Delete Files
This step depends on your requirements. For me, we will delete the generated files. Using System.IO.File, we will delete the text files. After the using ZipFile zip = new ZipFile()) code block, we'll add the following lines:
for (int i = 1; i <= 5; i++)
{
File.Delete(textFileNameTemplate + i + ".txt");
}
My code probably isn't the most optimized code. But it works. If anyone can suggest a better code that would be great. But for now, I'll be using this code. Many thanks! Especially to Sachu, a really helpful person.

Generating an Excel File, then Downloading it From Browser in ASP.NET MVC Application

So I have this page on my application where the user can download a "hard copy" of a rendered view, which represents Skills and their Requirements on Roles within a Project, showing the fulfilment of said Skills by any people on the Role.
I have the functionality working with a csv file, as I can just use a StringBuilder for creating a comma-delimited file.
However, before approaching the Excel approach, where I want some light formatting, I realise I cannot acheive this the same way.
I have used Interop for generating Excel files before, but how would I be able to create one that can be downloaded after it's generation?
Here is the working code to generate and return a CSV file:
public ActionResult DownloadSQEPToCSV(int projectID)
{
//source my data
StringBuilder sBuilder = new StringBuilder();
sBuilder.Append("SQEPMatrix, For Project," + data.First().Project.ContractNumber);
foreach (var role in data)
{
sBuilder.Append("\r\nRole:," + role.First().Title.Name);
sBuilder.Append("\r\nSkill,Requirement");
foreach (var person in role.Distinct(uCom))
{
sBuilder.Append("," + person.User.UserDetail.Name);
}
foreach (var skill in role.Distinct(uCom))
{
//More stuff to generate what I want
}
sBuilder.Append("\r\n");
}
//Attach file to the header
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment;filename=SQEPMatrix for " + data.First().Project.ContractNumber + ".csv");
Response.ContentType = "text/csv";
Response.Write(sBuilder);
Response.End();
return SetTitleAndID("SQEP","dl_sqep_csv");
}
This code is invoked by the following script:
function download(id) {
window.location.href = '../../Project/DownloadSQEPExcel?projectID=' + id;
}
So my question, is how can I generate an Excel spreadsheet, and return the generated file in a manner similar to how I return my .csv file?
If you use something like DocumentFormat.OpenXml you can create the Excel file in a memory stream and then return the stream using a FileStreamResult:
var theStreamContainingSpreadsheet = CreateSpreadsheet();
theStreamContainingSpreadsheet.Position = 0;
return new FileStreamResult(theStreamContainingSpreadsheet, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{FileDownloadName = "Export.xlsx"};

Categories

Resources