Allow Client to Download Excel File - c#

I'm using EPPLUS to generate an Excel File. I have code to save it to the server but I can't figure out how to allow the client to download the Excel sheet.The user clicks the button and it downloads to where ever they have it set in their browser. I found the client download code here that I can't get to work...It's not throwing an error in Firebug or Fiddler
JQuery
$('#ExcelExport').on('click', function () {
$.post("/Reports/ExportToExcel", function (data) {
alert("The Export was Succussful");
})
.fail(function () {
alert("The Export has Failed");
});
C#
public ActionResult ExportToExcel()
{
using (ExcelPackage package = new ExcelPackage())
{
// Get Data
var excelData = _repository.ExcelData();
//Basic Info
package.Workbook.Properties.Author = "MEO System";
package.Workbook.Properties.Title = "PendingMEOs";
//Excel worksheet
package.Workbook.Worksheets.Add("Pending MEOs");
ExcelWorksheet ws = package.Workbook.Worksheets[1]; // 1 is the position of the worksheet
ws.Name = "Pending MEOs";
//adds the data to the excel sheet and formats the data
ws.Cells.LoadFromCollection(excelData, true, OfficeOpenXml.Table.TableStyles.Medium6);
//sets the cell width to fit the contents
ws.Cells["A1:L" + excelData.Count()].AutoFitColumns();
// Save the Excel file
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=PendingMEOS.xlsx");
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.BinaryWrite(package.GetAsByteArray());
Response.End();
}
return Json(new { success = true });
}
Save Code to the server, works but not what I want
string path = "C:\\PendingMEOS.xlsx";
Byte[] bin = package.GetAsByteArray();
System.IO.File.WriteAllBytes(path, bin);

The problem is you are writing directly to the Response stream but then return a Json result.
Take a look at MVC Controller Using Response Stream

Related

How to download an excel in a chrome browser having options as Open, Save and Cancel as i used closed Xml in C#?

How to download an excel in a chrome browser having options as Open, Save and Cancel as I used closed Xml in C#?
public FileResult ExportToExcel(List<MyStudentList_Result> StudentList)
{
List<string[]> titles = new List<string[]> { new string[] { "name", "Number", "Type", "syllabus", "Title", "Added" } };
byte[] fileStream = ExportToExcel(StudentList, "StudentList", titles);
string mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AppendHeader("Content-Disposition", "inline; filename=" + "StudentList.xlsx");
return File(fileStream, mimeType);
}
public byte[] ExportToExcel(List<MystudentList_Result> StudentList, string worksheetTitle, List<string[]> titles)
{
var wb = new XLWorkbook(); //create workbook
var ws = wb.Worksheets.Add(worksheetTitle); //add worksheet to workbook
var rangeTitle = ws.Cell(1, 1).InsertData(titles); //insert titles to first row
rangeTitle.AddToNamed("Titles");
var titlesStyle = wb.Style;
titlesStyle.Font.Bold = true; //font must be bold
// titlesStyle.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; //align text to center
wb.NamedRanges.NamedRange("Titles").Ranges.Style = titlesStyle; //attach style to the range
if (StudentList!= null && StudentList.Count() > 0)
{
//insert data to from second row on
ws.Cell(2, 1).InsertData(StudentList);
ws.Columns().AdjustToContents();
}
//save file to memory stream and return it as byte array
using (var ms = new MemoryStream())
{
wb.SaveAs(ms);
return ms.ToArray();
}
}
You can guide what the browser does with the Content-Disposition header. For saving the file you should use attachment:
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);

MVC pasting HTML to excel

I have a html content which I would like to export as excel file. My function for exporting to excel looks like this:
public ActionResult ExportToExcel(string htmlToExport)
{
using (ExcelPackage ep = new ExcelPackage())
{
string fileTemplate = "test.xlsx";
using (FileStream stream = new FileStream(HttpContext.Server.MapPath("~/") + ConfigurationManager.AppSettings["templatePath"] + fileTemplate, FileMode.Open))
{
ep.Load(stream);
}
ExcelWorksheet ws = ep.Workbook.Worksheets.First();
Response.AppendHeader("Content-Disposition", fileTemplate);
return File(ep.GetAsByteArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}
}
Is there a way to paste html to excel file? If I do this manually, everything is OK. I would like to do this on the server side and return excel file with pasted html inside. Is this possible?
Of course it's possible. My code sample is below;
public ActionResult BankAccountReport(BankAccountsInfoFilter bankAccountsInfoFilter)
{
var bankAccountInfos = service.GetBankAccounts(bankAccountsInfoFilter);
DetailReportExport(bankAccountInfos);
return new EmptyResult();
}
[NonAction]
public void DetailReportExport(List<BankAccountViewModel> bankAccountInfos)
{
string html = RenderPartialViewToString("_BankAccountDetailReport", bankAccountInfos);
Response.ClearContent();
Response.AddHeader("content-disposition", "attachment; filename=BankAccountInfoDetailReport.xls");
Response.ContentType = "application/excel";
Response.AddHeader("content-language", "tr-TR");
Response.ContentEncoding = System.Text.Encoding.UTF8;
Response.BinaryWrite(System.Text.Encoding.UTF8.GetPreamble());
Response.Write(html);
}

Error dialog displayed when opening an excel file generated with EPPlus

I am creating an Excel file using the EPPlus library. When I create file and open up the file, the following pop up message shows:
We found a problem with some content in 'ExcelDemo.xlsx'. Do you want us to try to recover as much as we can? If you trust the source of this workbook, Click Yes
I am using following code
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[1, 2].Value = "Excel Download";
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=ExcelDemo.xlsx");
Response.BinaryWrite(pck.GetAsByteArray());
}
Is there problem in my code or is this an Excel issue?
In my case the problem was in calling
package.Save();
and using
Response.BinaryWrite(package.GetAsByteArray());
at the same time.
When you call package.GetAsByteArray() it perfoms following operations internally:
this.Workbook.Save();
this._package.Close();
this._package.Save(this._stream);
So, calling package.Save two times leads to this error when opening in Excel.
At the start, you need to add in a:
Response.Clear();
Then at the end add a
Response.End();
I will share my solution. I am using a template excel file and then create new excel from it.
Receiving the same error. My code was
using (Stream newFileStream = File.Open(this.tempFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
using (Stream originalFile = File.Open(this.initialFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (ExcelPackage excelPackage = new ExcelPackage(newFile, template))
{
// ... Do work here
}
I had to change code to:
FileInfo intialInfo = new FileInfo(this.initialFilePath);
FileInfo tempFileInfo = new FileInfo(this.tempFilePath);
using (ExcelPackage excelPackage = new ExcelPackage(tempFileInfo, intialInfo))
{
//... Do work here
}
Also I am using ASP MVC and the response is:
byte[] result = exporter.GetBytesFromGeneratedExcel();
return this.File(result, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Test.xlsx");
In my case, problem was data table name which I did not set earlier.
Try this one,
dt.TableName = "ExcelSheet1";
I was having this problem because I was writing a string larger than 32,767 characters into a single cell. Excel doesn't like this, but EPPlus won't stop you from doing it.
My code was updated... and was getting the same error.... and I finally found my solution
Original Code:
public static void ExportToExcel(HttpContext ctx, DataTable tbl, string fileName)
{
try
{
using (ExcelPackage pck = new ExcelPackage())
{
//Create the worksheet
ExcelWorksheet ws = pck.Workbook.Worksheets.Add(fileName);
//Load the datatable into the sheet, starting from cell A1. Print the column names on row 1
ws.Cells["A1"].LoadFromDataTable(tbl, true);
int rowCount = tbl.Rows.Count;
List<int> dateColumns = new List<int>();
foreach (DataColumn d in tbl.Columns)
{
if (d.DataType == typeof(DateTime))
dateColumns.Add(d.Ordinal + 1);
}
CultureInfo info = new CultureInfo(ctx.Session["Language"].ToString());
foreach (int dc in dateColumns)
ws.Cells[2, dc, rowCount + 1, dc].Style.Numberformat.Format = info.DateTimeFormat.ShortDatePattern;
//Write it back to the client
ctx.Response.Clear();
ctx.Response.AddHeader("content-disposition", "attachment; filename=" + fileName + ".xlsx");
ctx.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
ctx.Response.Buffer = false;
ctx.Response.BufferOutput = false;
ctx.Response.BinaryWrite(pck.GetAsByteArray());
ctx.Response.End();
}
}
catch (Exception EX)
{
ctx.Response.Write(EX.ToString());
}
}
Code update:
catch (Exception EX)
{
if (!(EX is System.Threading.ThreadAbortException))
{
ctx.Response.Write(EX.ToString());
}
}
IT WORKED!
A solution I came up with was just returning the file object in the controller. The first argument should be the byte array (file), the second argument is the content type, and the last argument is the filename (in my case "report.xlsx").
return File(file, "application/octet-stream", fileName);
Hope this helped.

Opening a client-side Excel file using EPPlus

I am the middle of writing a program which has to create an excel file on a client machine and then, after they have saved and updated it then I need to import it again and apply the changes to my database. The export bit of it works fine, however when I import from the web application I get zero worksheets in my workbook. If I run it on my development machine, i.e. the website is running on the same machine as the file is located then it works fine.
My code is as follows:
try
{
Productsfile = new FileInfo(PathandFileName);
}
catch (Exception ex)
{
lblStatus.Text = string.Format("Error getting file info {0}", ex.Message);
return;
}
lblStatus.Text += "File Opened succesfully " + Productsfile.FullName + Environment.NewLine;
//Open and read file
try
{
using (ExcelPackage datafile = new ExcelPackage(Productsfile))
{
ExcelWorkbook wkb = datafile.Workbook;
if (wkb != null)
{
lblStatus.Text += string.Format("The workbook is not null and there are {0} worksheets", wkb.Worksheets.Count) + Environment.NewLine;
I have confirmed that the code gets to the last label update, which tells me there are zero worksheets in the workbook, but importantly that the workbook itself is not null.
When we created the export the following code was used, which transfers the data stream from server to client - I am wondering if something to reverse it is needed:
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=Products.xlsx");
Response.BinaryWrite(pck.GetAsByteArray());
Response.End();
Right, I believe I've found the answer:
1) Get the file details from a fileupload control
2) Convert this to a memory stream
3) Create the package using the memory stream
And the code is as follows:
if (FileUpload1.HasFile)
{
HttpPostedFile file = Request.Files[0];
myLabel.Text = file.FileName;
MemoryStream mem = new MemoryStream();
mem.SetLength((int)file.ContentLength);
file.InputStream.Read(mem.GetBuffer(), 0, (int)file.ContentLength);
ExcelPackage package = new ExcelPackage(mem);
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
myLabel.Text += " " + worksheet.Name;
}

Download EXCEL file from ASP.NET page without Generating physical file on server (On The Fly)

I am trying to export C# DataTable to EXCEL file on the fly (without creating physical file) using Microsoft Office EXCEL INTEROP and download it through asp.net webpage through Response object. I am able to generate memorystream using the library But somehow the file is not getting saved through the memory stream. Reference code is given below. You will be required to take reference for DocumentFormat.OpenXml.dll & WindowsBase.DLL (that you can download from microsoft site).
Any Idea how to resolve the problem ? ? ?
Private void DownloadFile()
{
DataSet objTable = ReadTableFromViewstate();
if (objTable != null && objTable.Rows.Count > 0)
{
string strDownloadableFilename = "TestExcelFileName.xls";
MemoryStream fs1 = new MemoryStream();
if (CreateExcelFile.CreateExcelDocument(objTable, fs1))
{
Response.Clear();
byte[] data1 = new byte[fs1.Length];
fs1.Read(data1, 0, data1.Length);
fs1.Close();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", strDownloadableFilename));
Response.BinaryWrite(data1); ;
Response.End();
}
else
{
LblErrorMessage.Text = "Error Exporting File.";
}
}
}
..
public static bool CreateExcelDocument(DataSet ds, System.IO.Stream excelFileStream)
{
try
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(excelFileStream, SpreadsheetDocumentType.Workbook))
{
CreateParts(ds, document);
}
Trace.WriteLine("Successfully created: " + excelFileStream);
return true;
}
catch (Exception ex)
{
Trace.WriteLine("Failed, exception thrown: " + ex.Message);
return false;
}
}
..
private static void CreateParts(DataSet ds, SpreadsheetDocument document)
{
WorkbookPart workbookPart = document.AddWorkbookPart();
Workbook workbook = new Workbook();
workbookPart.Workbook = workbook;
// If we don't add a "WorkbookStylesPart", OLEDB will refuse to connect to this .xlsx file !
WorkbookStylesPart workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>("rIdStyles");
Stylesheet stylesheet = new Stylesheet();
workbookStylesPart.Stylesheet = stylesheet;
Sheets sheets = new Sheets();
// Loop through each of the DataTables in our DataSet, and create a new Excel Worksheet for each.
uint worksheetNumber = 1;
foreach (DataTable dt in ds.Tables)
{
// For each worksheet you want to create
string workSheetID = "rId" + worksheetNumber.ToString();
string worksheetName = dt.TableName;
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>(workSheetID);
WriteDataTableToExcelWorksheet(dt, worksheetPart);
Sheet sheet = new Sheet() { Name = worksheetName, SheetId = (UInt32Value)worksheetNumber, Id = workSheetID };
sheets.Append(sheet);
worksheetNumber++;
}
workbook.Append(sheets);
}
Thanks to All, Finally I Got solution of my problem. I just replaced following line of code:
byte[] data1 = new byte[fs1.Length];
fs1.Read(data1, 0, data1.Length);
fs1.Close();
with this line
byte[] data1 = fs1.ToArray();
and my problem got resolved.
After finishing writing to the memory stream, you need to set back the pointer to its origin before reading it.
fs1.Seek(0, SeekOrigin.Begin);

Categories