Problem
I'm trying to send a List to an Excel file by using the LoadFromCollection method.
After I generate an XLSX file, it does not open but if I change the extension to XLS, it appears like this.
ExcelFileError
Code
[HttpGet]
[Route("GetExcel")]
public async Task<HttpResponse> GetExcel()
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
var stream = new MemoryStream();
using (var excelPackage = new ExcelPackage())
{
ExcelWorksheet ws = excelPackage.Workbook.Worksheets.Add("SoftwareVersao");
var result = await _versaoAppService.Selecionar();
ws.Cells["A1"].LoadFromCollection(result);
ws.Cells.AutoFitColumns();
excelPackage.SaveAs(stream);
}
HttpContext.Current.Response.BinaryWrite(stream.ToArray());
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=" + "SoftwareVersao.xlsx");
HttpContext.Current.Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();
return HttpContext.Current.Response;
}
This code generates a corrupted XLSX file if I change the lines below it generates the above image.
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=" + "SoftwareVersao.xls");
Attempts
I've made several attempts.
I used HttpResponseMessage instead of HttpResponse
I used a blank template in creating the file
I changed the enconding
I used several code snippets
What am I doing wrong? Is there something I forgot to implement?
Update
I found this question and now could generate the XLSX file, but I'm having the same problem that the author of the question, where Excel have to repair the file.
WebApi using EF EPPlus returning gibberish in exce
Related
We're using SSRS 2017 as our report server with ReportService2010.asmx and ReportExecution2005.asmx as the web references. When I export the report to Excel in the reporting server or project, it exports to .xlsx file and I'm able to open it without any issues but when I export the report to .xlsx (EXCELOPENXML) using a web forms app (C#), it exports the report but shows an alert "We found a problem with some content..." (see image) when opening the file. If I say, "Yes", excel repairs the file and shows the correct data. Error log is also not very helpful.
I don't know what is causing the web forms app to export an corrupted .xlsx file. Any help is appreciated. Thanks.
I had to Flush and Close the HttpResponse request for it to work.
response.OutputStream.Flush();
response.OutputStream.Close();
response.Flush();
response.Close();
This is what worked for me.
private void executeReport(String reportName, ParameterValue[] rptParams, String rptFormat, string strRptFileName, ReportExecutionService service)
{
string encoding;
string mimeType;
string extension;
Warning[] warnings = null;
string[] streamIDs = null;
string historyID = null;
ExecutionInfo execInfo = new ExecutionInfo();
ExecutionHeader execHeader = new ExecutionHeader();
service.ExecutionHeaderValue = execHeader;
execInfo = service.LoadReport(reportName, historyID);
service.SetExecutionParameters(rptParams, "en-us");
String SessionId = service.ExecutionHeaderValue.ExecutionID;
byte[] result = service.Render(rptFormat, null, out extension, out encoding, out mimeType, out warnings, out streamIDs);
Response.ClearContent();
Response.Clear();
if (rptFormat == "EXCELOPENXML")
{
Response.AppendHeader("content-disposition", "attachment; filename=" + strRptFileName + ".xlsx");
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
Response.BinaryWrite(result);
Response.Flush();
Response.SuppressContent = true;
try
{
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
catch (ThreadAbortException ex)
{
//ignore
}
}
I am generating Excel files using OpenXML, the file opens without any issues on my desktop with Excel 2016 installed. The file also passes validation using Open XML Productivity Tool 2.5.
The problem is that the file is rejected from the SQL Server Integration Services (SSIS) processing. The error is "External table is not in the expected format"
As far as I know SSIS is using OLEDB to process the files.
I have tried to read the file locally using the following code and was able to reproduce the same error.
The code is as follows:
var fileName = "C:\\Temp\\myExcel.xlsx";
var connectionString = String.Empty;
if (Path.GetExtension(fileName) == ".xlsx")
{
connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;HDR=YES;\"", fileName);
}
else //.xls
{
connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=YES;IMEX=1;\"", fileName);
}
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
var adapter = new OleDbDataAdapter("select * from [test$]", conn);
var excelDataSet = new DataSet();
adapter.Fill(excelDataSet, "anyNameHere");
var data = excelDataSet.Tables["anyNameHere"];
foreach (DataRow row in data.Rows)
{
Console.Out.WriteLine(row[NAME].ToString());
}
}
All I was able to find in the net that this error is due to wrong connection string (Microsoft.Jet.OLEDB.4.0 and Excel 8.0 instead of Microsoft.ACE.OLEDB.12.0 and Excel 12.0) but I already have this.
This is definitely something wring with the file itself. The problem disappears if I open the file in Excel, and use save as.
I was trying to unpack the original and resaved files and compare the contents but the difference is huge, when saving excel adds lots of styles, themes, and xmls references. I really would not like to follow that path.
Do you know what parts are important for OleDB provider when reading Excel??
I am trying to write a C# Azure Function to download and open an excel file using the OpenXml-SDK.
Office Interop doesn't work here because office is not available to the Azure Function.
I am trying to use OpenXml-SDK to open and read the file which seems to require a path to the saved file and not the url or a Stream downloaded from the remote url.
Given I don't know of a way to temporary store the excel file in Azure Functions, I used Azure File Storage.
I uploaded the excel file from the url to Azure File Storage, however I cannot open the excel file with OpenXML-SDK.
I tested the excel file in Azure File Storage is working, however, when I try to open the OpenXML.SpreadsheetDocument form a MemoryStream I get error indicating the file is corrupt.
If I try to open the SpreadsheetDocument passing the file Uri (https://learn.microsoft.com/en-us/azure/storage/storage-dotnet-how-to-use-files#develop-with-file-storage) then the address passes the 260 character limit.
I'm open to using a library other than OpenXML and ideally I would prefer not to have to store the excel file.
Open XML SDK works fine in Azure Function. I tested it on my side. Here is the full code.
#r "DocumentFormat.OpenXml.dll"
#r "WindowsBase.dll"
using System.Net;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
WebClient client = new WebClient();
byte[] buffer = client.DownloadData("http://amor-webapp-test.azurewebsites.net/Content/hello.xlsx");
MemoryStream stream = new MemoryStream();
stream.Write(buffer, 0, buffer.Length);
stream.Position = 0;
using (SpreadsheetDocument doc = SpreadsheetDocument.Open(stream, false))
{
WorkbookPart workbookPart = doc.WorkbookPart;
SharedStringTablePart sstpart = workbookPart.GetPartsOfType<SharedStringTablePart>().First();
SharedStringTable sst = sstpart.SharedStringTable;
WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
Worksheet sheet = worksheetPart.Worksheet;
var cells = sheet.Descendants<Cell>();
var rows = sheet.Descendants<Row>();
log.Info(string.Format("Row count = {0}", rows.LongCount()));
log.Info(string.Format("Cell count = {0}", cells.LongCount()));
// One way: go through each cell in the sheet
foreach (Cell cell in cells)
{
if ((cell.DataType != null) && (cell.DataType == CellValues.SharedString))
{
int ssid = int.Parse(cell.CellValue.Text);
string str = sst.ChildElements[ssid].InnerText;
log.Info(string.Format("Shared string {0}: {1}", ssid, str));
}
else if (cell.CellValue != null)
{
log.Info(string.Format("Cell contents: {0}", cell.CellValue.Text));
}
}
}
return req.CreateResponse(HttpStatusCode.OK, "Hello ");
}
To use Open XML, please make sure you have created a bin folder under your function folder and uploaded DocumentFormat.OpenXml.dll and WindowsBase.dll to it.
"File contains corrupted data".
Have you tried another excel file to check whether the issue is related to specific excel file. I suggest you create a new simple excel to test your code again.
"It didn't work on my file with the same "File contains corrupted data" message. "
I download your excel file and found that it is a older version(.xls) of excel file.
To fixed the exception, you could convert the excel to latest version(.xlsx) or choose another excel parse library. ExcelDataReader could work for any versions of excel file. You could install this library using NuGet by searching 'ExcelDataReader'. Following is the sample code of how to parse .xls format excel file. I tested it on Azure Function, it did worked fine.
#r "Excel.dll"
#r "System.Data"
using System.Net;
using System.IO;
using Excel;
using System.Data;
public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
WebClient client = new WebClient();
byte[] buffer = client.DownloadData("http://amor-webapp-test.azurewebsites.net/Content/abcdefg.xls");
MemoryStream stream = new MemoryStream();
stream.Write(buffer, 0, buffer.Length);
stream.Position = 0;
IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);
DataSet result = excelReader.AsDataSet();
for (int i = 0; i < result.Tables.Count; i++)
{
log.Info(result.Tables[i].TableName +" has " + result.Tables[i].Rows.Count + " rows.");
}
return req.CreateResponse(HttpStatusCode.OK, "Hello ");
}
Please add "Excel.dll" file to the bin folder of your function before executing upper code.
If you do need to save a temporary file, Azure Functions has a %TEMP% environment variable with a path to a temporary folder. This is a folder that is local to the vm that runs your function and will not be persisted.
However, saving the file locally / in Azure Files is unnecessary. You should be able to get the stream from the response to your get request and pass it straight to OpenXML.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(originalExcelUrl);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
{
var doc = SpreadsheetDocument.Open(stream, true);
// etc
}
Excel files are stored in azure blob containers. They are downloaded without incident in IE but in Chrome the page displays this message (and in Canary it crashes):
This file appears corrupt
and provides a link to download it and all is well from that point. I've tried setting the content-type to different excel formats but the result is the same.
Here's the blob code:
MemoryStream memoryStream = new MemoryStream();
CreateFile(memoryStream, grid);
memoryStream.Position = 0;
var blockBlob = container.GetBlockBlobReference(randomFileName);
blockBlob.Properties.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
blockBlob.DeleteIfExists();
var options = new BlobRequestOptions()
{
ServerTimeout = TimeSpan.FromMinutes(10)
};
try
{
blockBlob.UploadFromStream(memoryStream, null, options);
}
catch (Exception e)
{
_logger.Error("Uploading excel file: Error: {0}", e.Message);
}
return new Uri("https://myblobs.blob.core.windows.net/" + "containername/" + randomFileName);
You missed blockBlob.SetProperties();
Try this:
var blockBlob = container.GetBlockBlobReference(randomFileName);
blockBlob.DeleteIfExists();
blockBlob.Properties.ContentType =
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
blockBlob.SetProperties(); // This is for commiting changes.
Note that for .xls files you need to set content-type to application/vnd.ms-excel.
FYI: If you want to update property values in existing blob you need to fetch the current values, set the property that we want to update and call SetProperties on the BLOB.
Example:
blob.FetchAttributes();
blob.Properties.ContentType = "image/png";
blob.SetProperties();
the file you are trying to open is in a different format than specified by the file extension c# error when trying to open file in excel.
Here is my code
public ActionResult Export(string filterBy)
{
MemoryStream output = new MemoryStream();
StreamWriter writer = new StreamWriter(output, Encoding.UTF8);
var data = City.GetAll().Select(o => new
{
CountryName = o.CountryName,
StateName = o.StateName,
o.City.Name,
Title = o.City.STDCode
}).ToList();
var grid = new GridView { DataSource = data };
grid.DataBind();
var htw = new HtmlTextWriter(writer);
grid.RenderControl(htw);
writer.Flush();
output.Position = 0;
return File(output, "application/vnd.ms-excel", "test.xls");
}
when am trying to open excel i get this error
the file you are trying to open is in a different format than
specified by the file extension
After clicking on Yes the file open properly. but i don't want this msg to appear.
I have used CloseXML to solve the problem.
public static void ExportToExcel(IEnumerable<dynamic> data, string sheetName)
{
XLWorkbook wb = new XLWorkbook();
var ws = wb.Worksheets.Add(sheetName);
ws.Cell(2, 1).InsertTable(data);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("content-disposition", String.Format(#"attachment;filename={0}.xlsx",sheetName.Replace(" ","_")));
using (MemoryStream memoryStream = new MemoryStream())
{
wb.SaveAs(memoryStream);
memoryStream.WriteTo(HttpContext.Current.Response.OutputStream);
memoryStream.Close();
}
HttpContext.Current.Response.End();
}
Installed ClosedXML in my project using Nuget Package Manager.
the file you are trying to open is in a different format than
specified by the file extension
You are constantly getting that warning message because the file that got created is not an actual excel file. If you will look into the generated file, it's just a bunch of html tags. Remember that a GridView's RenderControl will generate an html table.
To fix your issue, you need to either use a third party tool that creates a real excel file (one tool you might want to use is NPOI) or create a comma-delimited file, or simply a csv file, and return that file.
In case someone else stumbles across this... I needed to convert blobs back into files on-the-fly in C#. Pdf's worked well and excel gave me this same error as OP explains.
This is the code I wrote which handles excel differently from other file types.
Giving excel application/octet-stream with an actual filename solved my issue. Probably not the cleanest way to do it but it was good enough for my purposes.
string theExt = Path.GetExtension(theDoc.documentFileName).ToUpper();
Response.Clear();
if (theExt == ".XLS" || theExt == ".XLSX"){
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", string.Format("inline; filename={0}", theDoc.documentFileName));
}
else{
Response.ContentType = theDoc.documentMimeType;
Response.AddHeader("Content-Disposition", string.Format("inline; filename={0}", theDoc.documentTitle));
}
using (MemoryStream stream = new MemoryStream(theDoc.file))
{
stream.WriteTo(Response.OutputStream);
stream.Close();
};
Response.End();
In case someone needs to export a dataset as excel file with CloseXML.
Dataset ds = { your data from db }
var xlsx = new XLWorkbook();
var dataTable = ds.Tables[0];
xlsx.Worksheets.Add(dataTable);
xlsx.SaveAs("export.xlsx");