Using ASP.NET web page, I am exporting some data to excel spreadsheet (XLSX). The code is running fine when I run it using Visual Studio (it is exporting a XLSX file with correct data), but the same code fails when deployed to Testing Server.
It is not throwing any error, it simply exports a blank XLSX file.
Note: While debugging in the test server, I found that the data is getting fetched and temp file is also getting created properly, but the data is not getting written to the temp file (the weird thing is it doesn't through any error).
Added later
After doing some more research, I have found that there is no issue with small record set (say 1000, 2000). But when tried with ~20K records, I get a blank file.
I have been burning myself for last 2 days, someone rescue me :) ...
Code
string templateFile = #"C:\Templates\ExportFile.xlsx";
string tempFileName = Path.Combine(#"C:\Temp\", Path.GetRandomFileName());
tempFileName = Path.ChangeExtension(tempFileName, ".xlsx");
File.Copy(templateFile, tempFileName);
List<Customer> customerList = FetchCustomers();
DataTable dataTableObj = new DataTable("Customers$");
dataTableObj.Columns.Add(new DataColumn("CustomerID"));
dataTableObj.Columns.Add(new DataColumn("FirstName"));
dataTableObj.Columns.Add(new DataColumn("LastName"));
dataTableObj.Columns.Add(new DataColumn("CreatedDate"));
foreach (Customer customerObj in customerList)
{
DataRow dataRowObj = dataTableObj.NewRow();
dataRowObj["CustomerID"] = customerObj.CustomerID;
dataRowObj["FirstName"] = customerObj.FirstName;
dataRowObj["LastName"] = customerObj.LastName;
dataRowObj["CreatedDate"] = customerObj.CreatedDate;
dataTableObj.Rows.Add(dataRowObj);
}
using (OleDbConnection oleDbConnectionObj = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + tempFileName + ";Extended Properties=\"Excel 12.0 Xml;HDR=YES;\""))
{
OleDbCommand insertCommand = new OleDbCommand();
insertCommand.Connection = oleDbConnectionObj;
insertCommand.CommandText = #"INSERT INTO [Customers$] ([CustomerID], [FirstName], [LastName], [CreatedDate]) VALUES (?, ?, ?, ?)";
insertCommand.Parameters.Add("CustomerID", OleDbType.Numeric, 0, "CustomerID");
insertCommand.Parameters.Add("FirstName", OleDbType.VarChar, 0, "FirstName");
insertCommand.Parameters.Add("LastName", OleDbType.VarChar, 0, "LastName");
insertCommand.Parameters.Add("CreatedDate", OleDbType.Date, 0, "CreatedDate");
DataSet dataSetObj = new DataSet();
dataSetObj.Tables.Add(dataTableObj);
OleDbDataAdapter dataAdapter = new OleDbDataAdapter();
dataAdapter.InsertCommand = insertCommand;
dataAdapter.Update(dataSetObj, "Customers$");
}
Response.Clear();
Response.Buffer = true;
Response.ContentType = "application/vnd.ms-excel";
Response.Charset = "";
Response.AddHeader("Content-Disposition", "attachment; filename=Customers.xlsx");
Response.WriteFile(tempFileName);
Response.Flush();
Response.End();
Finally it got resolved!!!
While creating large XLSX file (greater then ~1MB), OLEDB Provider tries to create temp file at Local Settings\Temporary Internet Files\Content.MSO\ for the APP POOL account. If the folder doesn't exists or the APP POOL account doesn't have proper permission, then it fails without throwing errors (no idea why it doesn't throw error).
In my case Content.MSO folder was missing at C:\Documents and Settings\Default User\Local Settings\Temporary Internet Files.
I created the folder and gave the modify permission to NETWORK SERVICES..... and "Voila!" - everything started working.
Thanks to the below 2 links, they saved me days...:)
Microsoft ACE OLEDB connection creating empty Excel when there are 166,110 rows
http://www.rapidsnail.com/developer/topic/2011/109/2/65194/excel-writes-secret-use-oledb-write-data-to-excel-more-than-13571-line-file-for-blank.aspx
Related
I have a requirement where I need to format input files from different resources. My application receives input (xls/xlsx/ibfs) files through file upload and performs condition checks and generates formatted output in .xlsx file format. All my input files are reports generated by different online public data reporting websites. When I downloaded in excel format some websites are producing in “WFServlet.ibfs” file formats.
This is not a duplicate post. I tried different approaches and followed suggestions here and tried several ways but didn't solve my issue. Sorry for the long post. I want to have seniors advise or help to solve this problem.
I’m able to handle xls and xlsx file formats with using C# OLEDB ACE engine. It’s working perfectly fine in my local machine and also in my locally hosted IIS server. But when I upload .ibfs file formats I’m getting issues.
Sample input
Here I'm posting my most effective two different approaches:
Approach 1 (Using Microsoft Office Interop)
Approach 2 (Using third party EPPlus library)
1. Approach 1 (Using Microsoft Office Interop):
In this approach, I used Microsoft Interop dlls. Initially before conversion I changed the extension of .ibfs to .xls and then I used Microsoft Interop to convert xls into xlsx file format. In this approach its working fine in my local machine. But it’s not working in my local IIS server (In my local IIS server I’m able change the extension from .ibfs to .xls but after that it’s not creating xlsx file from xls). I added dlls of Office12 "Microsoft.Office.Interop.Excel.dll" and "Office.dll" to my project reference.
But with this approach I may have a problem in future. Currently Office is installed in my local machine, but when we move code to the server there we don’t have Office installed and client don’t want to install Office in the server. I'm not sure whether it will work in the server with the same dll's without installing the office.
Below is the code:
Step 1: Change extention from .ibs to .xls and call conversion method, if user uploaded file is .ibfs file type
string path ="C:\\testinput\\";
string extension = Path.GetExtension(InputFile.FileName); // get the extension of user upload file
string fileName = "testFile"+ extension; // make a new name to assign to the user uplaoded file
InputFile.SaveAs(path + fileName); // save the user uploaded file into the testinput folder with testFile file name
inputFileWithPath = path + fileName; // copy the path of saved file "C:\\testinput\\testFile+extenstion"
newPath = inputFileWithPath; // used if input file is of .ibfs or .xls extn
if (extension.Equals(".IBFS") || extension.Equals(".ibfs"))
{
//input user uploaded file extension is .ibfs , If file already exist in the upload folder path then delete the old one before File.Move
if (File.Exists(newPath + ".ibfs"))
{
File.Delete(newPath);
}
else
{
newPath = Path.ChangeExtension(inputFileWithPath, ".xls"); // chnage the file extension from .ibfs to .xls
File.Move(inputFileWithPath, newPath); // move the new file .xls to testinput path
inputFileWithPath = excelComm.convertExel(newPath); // convert the .xls file into .xlsx file format
}
}
Step 2 Now conversion logic from .xls to xlsx using Interop
public string convertExel(string FilePath)
{
string path = "";
var app = new Microsoft.Office.Interop.Excel.Application();
try
{
if (File.Exists(FilePath + "x")) // check if file with .xlsx is already exist, if exist delete it
{ File.Delete(FilePath + "x"); }
else
{
var wb = app.Workbooks.Open(FilePath);
wb.SaveAs(Filename: FilePath + "x", FileFormat: Microsoft.Office.Interop.Excel.XlFileFormat.xlOpenXMLWorkbook);
path = FilePath + "x";
wb.Close();
}
} // end of try
catch (Exception ex)
{
string errorMsg = "";
CatchException(ex, errorMsg);
}
return path;
}
2. Approach 2 (Using third party EPPlus library):
I downloaded EPPlus.dll and added to my project reference. I used below code. Which is basically changes the extension of .ibfs to xls and calls the convertExcel methods, where it converts the xls into dataset from that dataset , I copied data table into to the workbook sheet and saved it as .xlsx file. But it is not working.
Below is the code sample
Step 1: Change extension from .ibs to .xls and call conversion method, if user uploaded file is .ibfs file type
Step 1 is same as above as mentioned in Approach 1.
Step 2: Conversion from .xls to xlsx using EPPlus library. For this I followed solution from C# - convert xls file to xlsx without office components
public string convertExel(string FilePath)
{
string path = "";
try
{
if (File.Exists(FilePath + "x"))// check if file with .xlsx is already exist, if exist delete it
{File.Delete(FilePath + "x");}
else
{
string fileName = Path.GetFileNameWithoutExtension(FilePath);
string filePathXlsx = "C:\\testinput\\"+ fileName + ".xlsx ";
using (ExcelPackage epackage = new ExcelPackage())
{
ExcelWorksheet excel = epackage.Workbook.Worksheets.Add("Sheet1");
DataSet ds = ReadExcelFile(FilePath); // Causing Error HERE
DataTable dtbl = ds.Tables[0];
excel.Cells["A1"].LoadFromDataTable(dtbl, true);
System.IO.FileInfo file = new System.IO.FileInfo(filePathXlsx);
epackage.SaveAs(file);
path = filePathXlsx;
} // end of using
}// end of else
}//end of try
catch (Exception ex)
{
string errorMsg = "";
CatchException(ex, errorMsg);
}
return path;
} // end of method
// generate dataset from excel file
private static DataSet ReadExcelFile(string FilePath)
{
string constr = "";
DataSet ds = new DataSet();
string extension = Path.GetExtension(FilePath);
if (extension.Equals(".xls", StringComparison.CurrentCultureIgnoreCase))//Checking for the extentions, if XLS connect using ACE OleDB
{
constr = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + FilePath + ";Extended Properties=\"Excel 8.0;IMEX=1;HDR=YES\"";
}
//Use ACE OleDb if xlsx extention
else if (extension.Equals(".xlsx", StringComparison.CurrentCultureIgnoreCase))
{
constr = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;IMEX=1;HDR=YES\"", FilePath);
}
else
{
constr = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + FilePath + ";Extended Properties=\"Excel 8.0;IMEX=1;HDR=YES\"";
}
using (OleDbConnection conn = new OleDbConnection(constr))
{
conn.Open(); // causing error HERE
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
DataTable dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" }); // Get all Sheets in Excel File
foreach (DataRow dr in dtSheet.Rows) // Loop through all Sheets to get data
{
string sheetName = dr["TABLE_NAME"].ToString();
cmd.CommandText = "SELECT * FROM [" + sheetName + "]"; // Get all rows from the Sheet
DataTable dt = new DataTable();
dt.TableName = sheetName;
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(dt);
ds.Tables.Add(dt);
} // end of for
cmd = null;
conn.Close();
} // end of using
return ds;
}
Its giving me error “System.Data.OleDb.OleDbException (0x80004005): External table is not in the expected format.
at System.Data.OleDb.OleDbConnectionInternal..ctor(OleDbConnectionString constr, OleDbConnection connection)”
Its changing the extension from .ibfs to xls but after that its not generating any xlsx file. I tried with different connection strings, ACE, Jet engines with Xml format, HTML import, with single quotes and double quotes but nothing is working. Is it problem with the downloaded web excel file in any specific format which is not supported by OLEDB? I'm not sure how to handle such type of specific formats.
I appreciate if any one can give me any idea how I can solve the problem with the 'ibfs' file formats.
My Latest update: I tried with the Spire.XLS but it didn't work with '.ibfs' file formats. Its just working fine with xls and xlsx formats.
Just one request, please only suggest open-source dll's. I can't install any software in client machine (server). I have only option to use open-source libraries like EPPlus or anything supported by just dll's without any installation. Thank you.
Try replacing Extended Properties=\"Excel 12.0;IMEX=1;HDR=YES\" with Extended Properties=\"Excel 12.0 Xml;IMEX=1;HDR=YES\" in
//Use ACE OleDb if xlsx extention
else if (extension.Equals(".xlsx", StringComparison.CurrentCultureIgnoreCase))
{
constr = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;IMEX=1;HDR=YES\"", FilePath);
}
If IBFS files are Excel files, you can try using Essential XlsIO. I couldn't find any IBFS files to check with.
The whole suite of controls is available for free (commercial applications also) through the community license program if you qualify. The community license is the full product with no limitations or watermarks.
Note: I work for Syncfusion.
I have tool for parsing excel files. User chooses the xls/xlsx to be read, then my tool creates a copy of it in the temp with a random name, then actually parses the copy. The relevant part of the code:
string sourceFile = textBox1.Text;
string fileName = System.IO.Path.GetRandomFileName();
string destFile = System.IO.Path.Combine(Path.GetTempPath(), fileName + ".xlsx");
System.IO.File.Copy(sourceFile, destFile, true);
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook excelBook = xlApp.Workbooks.Open(destFile);
OleDbConnection cnn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + destFile + "; Extended Properties=Excel 12.0;");
string qText = #"select * from [sheet1$]";
OleDbCommand oconn = new OleDbCommand(qText, cnn);
cnn.Open();
OleDbDataAdapter adp = new OleDbDataAdapter(oconn);
DataTable dt = new DataTable();
adp.Fill(dt);
cnn.Close();
And then I start to work with the DataTable.
In case the original source files (not the copy) is open in excel, then the copy from the temp folder also opens up in excel. And here comes the strangest stuff. If it's closed during the script run, and then I open the original xls only from windows explorer, the copy from temp opens up again. Moreover, if I run the script e.g. 10 times (while original is closed), when I open it, all the 10 randomly named copies open up along with it. I suppose it's not due to the code itself, but some windows/office bug/feature.
Please advise.
You have two lines here that initializes and open the copy of your destination file
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook excelBook = xlApp.Workbooks.Open(destFile);
You should remove them. OleDb interaction with the Excel file doesn't need Interop to work.
By the way, when working with these ugly Interop variables I use a simple trick to shorten these names
using ExcelLib = Microsoft.Office.Interop.Excel;
.....
ExcelLib.Application xlApp = new ExcelLib.Application();
can not open excel file in c# because The file you are trying to open in a different format than specified file extension. Verify that the file is not corrupted and is from a trusted source before opening the file. Do you want to open the file now?
private void button1_Click(object sender, EventArgs e)
{
string fileName = Directory.GetCurrentDirectory();
fileName += "\\" + textBox1.Text + ".xls";
var connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName + ";Extended Properties=\"Excel 12.0;IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text\"";
var conn = new OleDbConnection(connectionString);
conn.Open();
var sheets = conn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
var cmd = conn.CreateCommand();
/////////////////////// sheet 1
cmd.CommandText = "SELECT * FROM [" + sheets.Rows[0]["TABLE_NAME"].ToString() + "] ";
var adapter = new OleDbDataAdapter(cmd);
var ds = new DataSet();
adapter.Fill(ds);
DataTable dt = new DataTable();
dt = ds.Tables[0];
}
This is because the file is actually basically just a CSV file with an XLS extension to make it open in Excel.
it happens in new versions of Excel. Older ones will happily export them.
See this Microsoft doc for more information:
http://support.microsoft.com/kb/948615
One option is simply to rename the file name to .csv, and keep the user interface as saying that it is an Excel file (Excel is quite happy to read csv files). Given that Windows tends to hide the file extension, this seems like a fairly attractive option.
EDIT
"External table is not in the expected format." typically occurs when trying to use an Excel 2007 file with a connection string that uses: Microsoft.Jet.OLEDB.4.0 and Extended Properties=Excel 8.0
Go through:
Excel "External table is not in the expected format."
Hope its helpful.
I am doing this to read :
private bool writetoven(string xlspath)
{
OleDbConnection excelConnection = new OleDbConnection(excelConnectionString)
try
{
OleDbCommand ocmd = new OleDbCommand("select * from [Sheet1$]", excelConnection);
excelConnection.Open();
OleDbDataReader odr = ocmd.ExecuteReader();
string vcode = "";
string pswd = "";
string vname = "";
while (odr.Read())
{
vcode = valid(odr, 0);
pswd = valid(odr, 1);
vname = valid(odr, 2);
insertdataintosql(vcode,pswd,vname);
}
excelConnection.Close();
return true;
}
catch (DataException)
{
return false;
}
finally
{
lblmsg4.Text = "Data Inserted Sucessfully";
}
}
and my connection string is like this:
excelConnectionString = "provider=Microsoft.jet.oledb.4.0;data source=" +
filepath1 +
";extended properties='Excel 8.0;HDR=YES;'";
but I am getting an error as
The Microsoft Jet database engine cannot open the file ''. It is already opened exclusively by another user, or you need permission to view its data.
Line 1574: OleDbConnection excelConnection = new OleDbConnection(excelConnectionString);
Line 1575:
Line 1576: excelConnection.Open();
Line 1577:
Line 1578:
It seems like the file is still open but its not and I have checked the running process and its not there
Now what should I do? ...My Excel sheet is closed but I am getting this error
i dont have microsoft access on my com is that can be an issue
is this problem is something to do with my fileupload control that i am using??
Well, the error says :
cannot open the file ''.
So it almost seems as if your Excel connection string isn't valid - it doesn't have a valid Excel file name in there!
When and where are you setting the Excel connection string??
Is the filepath1 you use valid in that moment?
Does it contain the valid Excel file name ??
Update: why I don't understand is: you're passing in xlspath as a parameter to your method - yet, you don't seem to use that xlspath anywhere - most certainly not to concatenate together your excelConnectionString ....
private bool writetoven(string xlspath)
{
OleDbConnection excelConnection = new OleDbConnection(excelConnectionString)
Can you put a breakpoint on this line - what does your excelConnectionString look like - just before your create the connection? Could it be that xlspath contains vendor.xls - but your Excel connection string just never even gets set to that value??
Make sure the account your web app is running under has permissions on the file.
Also, since you are not using a path, and just a filename, it might not be finding the file where it is at. Where is the file located relative to your web application?
Does System.IO.File.ReadAllBytes(filepath1) succeeed or fail?
Since you are dealing with a file upload:
The user is uploading from their computer through the browser, and the file is transferred to your server in the post response. See: http://blog.divergencehosting.com/2009/03/12/upload-read-parse-file-aspnet/
Even if you had the full path, you wouldn't be able to access the file on the user's computer from your server. The browser sends you a copy of the file in uploadControl.PostedFile.InputStream; where uploadControl is the name of your asp:FileUpload control.
You would then need to save this stream to a file location on the server, and provide this full path to the connection string.
If you used something like EPPlus to read the file instead of the OleDbConnection, you could use the in-memory stream instead of saving the file first.
Your excel file is open in the Microsoft Excel. Close the Excel window and everything will be fine.
// I want to use the SQL Query SELECT * FROM Table here, how can I do that?
string filepath = Server.MapPath("test.doc");
FileInfo file = new FileInfo(filepath);
// Checking if file exists
if (file.Exists)
{
// Clear the content of the response
Response.ClearContent();
// LINE1: Add the file name and attachment, which will force the open/cance/save dialog to show, to the header
Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
// Add the file size into the response header
Response.AddHeader("Content-Length", file.Length.ToString());
// Set the ContentType
Response.ContentType = ReturnExtension(file.Extension.ToLower());
// Write the file into the response (TransmitFile is for ASP.NET 2.0. In ASP.NET 1.1 you have to use WriteFile instead)
Response.TransmitFile(file.FullName);
// End the response
Response.End();
}
Can anyone help me with getting the contents of the table called Table in SQL Server 2008 and downloading it? I have the codes above, but currently it reads from a path, how to make it read from a SELECT query? The query in mind is "SELECT* FROM Table"
One way is to use a SQLDataReader (I'm not going to explain connections etc too here: I assume you've called a database before) and manually concatenate the columns
You'd normally use bcp.exe or perhaps SMO for this.
You could use SqlDataAdapter to fetch the data and populate a DataTable based on the data:
SqlConnection connection = new SqlConnection(connectionString);
string query = "SELECT * FROM Table";
SqlDataAdapter adapter = new SqlDataAdapter(query, connection);
connection.Open();
DataTable table = new DataTable();
try
{
adapter.Fill(table);
}
catch (Exception e)
{
throw e;
}
finally
{
connection.Close();
}
}