EPPlus InsertRow corrupts excel file - c#

I am currently comparing different files with each other and put the output in an Excel Workbook with multiple worksheets (one per file comparison) using EPPlus 4.5.3.3.
The worksheets are simple ranges - no tables.
Sometimes it is required to move the content of one Excel Sheet to a certain row in another Excel Sheet.
For this I am using the InsertRow function of EPPlus. The function itself does the trick and inserts the content at the desired row.
However, when opening the Workbook I receive these errors:
The content of that XML file is the following:
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
-<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<logFileName>error044200_02.xml</logFileName>
<summary>Errors were detected in file 'C:\Users\...\test.xlsx'</summary>
-<repairedParts>
<repairedPart>Repaired Part: /xl/worksheets/sheet5.xml part with XML error. Load error. Line 1, column 0.</repairedPart>
</repairedParts>
When I am adding the content at the last row without using InsertRow everything is working fine.
Also, if I save the ExcelPackage immediately after using InsertRow the error is also present, so it definitely has something to do with this function (also if I am only using one Worksheet). After using InsertRow it seems like the whole formatting of the respective Excel Sheet is screwed up. The inserted content appears to be right though.
The excel is initially created from an empty template excel that contains nothing but the header names (also had the same issue with a template without anything inside):
The following code can be used to reproduce (this is just an example - in my case every sheet has more than 50 rows):
FileInfo filePath= new FileInfo(fileName);
excel = new ExcelPackage(filePath);
ExcelWorkbook wb = excel.Workbook;
foreach (ExcelWorksheet ws in wb.Worksheets)
{
int i = 5;
ws.InsertRow(i, 1);
//same effect with ws.InsertRows(i, 1, i-1)
ws.Cells[i, 1].Value = "test";
ws.Cells[i, 2].Value = "test";
//excel.Save();
}
excel.Save();

Although my answer is not based on EPPlus, have you looked at this post ?
Inserting new rows and moving exsisting ones with OpenXML SDK 2.0
I am guessing that you are getting errors because the newly added rows from the ws.InsertRow function are not updating the required row indexes. This is mentioned in the post.
Also there is a recommendation in the comments "To anyone who is getting an error when opening the file try this line before you save your document'... xlsFile.WorkbookPart.DeletePart(xlsFile.WorkbookPart.CalculationChainPart);

Related

EPPlus Shows System Argument Exception

I am having issue reading in some worksheet from a workbook using C# and EPPlus.
Error Message
name contains invalid characters
Even after multiple checks on the worksheet name, file name and column headers within the workbook to make sure there is no invalid characters, I am still facing the same error.
However, when I move the worksheet that i need from that same workbook to a new Excel file and save it with the same file name and worksheet name, I have no error while reading in.
Does anybody know how to solve or even encounter this problem?
Code
using (ExcelPackage xlPackage = new ExcelPackage(mStream))
{
//WorksheetId = 5
var ws = xlPackage.Workbook.Worksheets[WorksheetId]; //This is the part that is causing error
for (int i = 1; i <= ws.Dimension.End.Column; i++)
{
dt2.Columns.Add((i - 1).ToString());
}
}
Came across this LINK and realized this is actually a bug in EPPlus for version 4.5.2.2 onward.
After reverting back to the older version, everything works fine.
There is a change the "name" as mentioned in the error is not the sheet name.. There is a section in the Formular tab of the Excel software called "Name Manager".
There you will find list of names and references there. The error above per the source code of EPPlus is generated when EPPlus tries to validate the name range.
I had to modify the EPPlus source code to ignore the error since the file i was dealing with was locked and needed to be preserved as it was.

How to solve Excel opening Error Generated by EPPlus .Net library

I am generating several excel copies from a template (its really big).
For that First I am taking the template from a file location, then based on a loop for every iteration I am creating a new ExcelPackage(newFile,Template).
After that I am taking the exact ExcelWorksheet that I have to edit.
Then after editing I am Saving as the file as newFile. The time of opening the saved file Two problem is occurring:
If there is no Excel instance is running on the PC then the saved file is opening but with no data.
If the Excel instance is running then the saved file is opening with Warning message but working. "Problem with some content with Excel. Do you want us to recover?" and "Excel was able to recover some unreadable content "
string templateExcel = #"Location\template.xlsx";
FileInfo templateFile = new FileInfo(#"Location\newFile.xlsx");
using (FileStream templateExcelStream = File.OpenRead(templateExcel))
{
using (ExcelPackage copyExcel = new ExcelPackage(templateExcelStream))
{
ExcelWorksheet presentWorkSheet = copyExcel.Workbook.Worksheets["Name"];
presentWorkSheet.Cells[4, 2].Value = Value from condition;
copyExcel.SaveAs(templateFile);
}
}
Thanks all of you for your valuable time. I got the solution.
For me the issue was in the template itself as it contained invalid references to lookup tables. I found this in Formula -> Name Manager.
I suggest that you check the template if you face this issue.

C# Excel Interop row limit -> HRESULT: 0x800A03EC exception thrown

I have a C# application which purpose is to store a big amount of data. I am using Microsoft.Office.Interop.Excel (Microsoft.Office.Interop.Excel.dll Version 14.0.0.0) to help me accomplish this. I have Excel 2007 installed.
I use the following lines:
excelApp = new Microsoft.Office.Interop.Excel.Application();
excelWorkBook = excelApp.Workbooks.Add(misValue);//*--------> LINE NOT WORKING */
excelWorksheetBeingWritten = (Excel.Worksheet)excelWorkBook.Worksheets.get_Item(1);
My code then iterates through a big list of objects, and each time a row must be written I do something like:
var startCell = excelWorksheetBeingWritten.Cells[excelLineCounter, 1];
var endCell = excelWorksheetBeingWritten.Cells[excelLineCounter, 2];
string[] tmpArray = new string[2] { stringVar1, stringVar2 };
tmpRange = excelWorksheetBeingWritten.Range[startCell, endCell];
tmpRange.Value = tmpArray;
When excelLineCounter exceeds 65536, the "HRESULT: 0x800A03EC exception" is thrown. I am perfectly aware of the (in)famous pre-Excel2007 row limit (which is precisely 65536). What I don't understand is why the interops are using that limit, when Excel 2007 (my version) has a documented limit of 1.048.576 rows.
On the other hand, if I replace the above "LINE NOT WORKING" by the following, it seems to use the Excel 2007 row limit, and the exception vanishes:
excelWorkBook = excelApp.Workbooks.Open(#"H:\Workbook1.xlsx");//*--------> LINE WORKING */
Note: "Workbook1.xlsx" is an empty workbook previously saved as "Excel Workbook (*.xlsx)"
Can someone please tell me what kind of sorcery do I need to do in order to configure the Excel Interop objects to use the Excel 2007 limits by default, preferably without having a previously saved empty .xlsx file laying around?
I encountered a similar issue yesterday and the solution is to change your Excel settings to create xlsx files by default.
In Excel: File -> Options -> Save -> Save files in this format
Your default is probably 'Excel 97-2003 (*.xls)' like mine was. If you change it to 'Excel Workbook (*.xlsx)', your code will work.

How to access data in sheet in my Visual Studio Office Excel workbook?

I need to create a "Document level customization" with C# code (not and Excel Add-in!)
I created a Visual Studio Office Excel 2010 Workbook project type. This creates a workbook with 3 sheets in my project. I added some "configuration" information to one of those sheets.
I need to access this configuration information programmatically (Sheet1 contains a button - pressing on that button should
load configuration data
open a WinForm
present configuration data on that form,
but somehow I can't find how to do that...
If I try to initialize Sheet1 class, compiler expects two parameters - Microsoft.Office.Tools.Excel.Factory and IServiceProvider, but I am calling this from a button that is placed on Sheet2 - so it's after Excel Workbook is already opened... shouldn't Sheet1 be initialized automatically?
So, how can I access Sheet1 from my VSTO project's c# code?
EDIT
Please see project sample screencast here
I have a button on Sheet2, that should
load some data from Sheet1
initialize WinForm
add it as a DataSource for a ComboBox on that WinForm
I can not find a way how to read data from that Sheet1...
It seems, that there are not a lot developers (at least at stackoverflow) that work with Excel workbooks in Visual Studio / VSTO), but still this is is how I got this basic stuff working - in case if this is helpful to someone else
Since my code was in the Worksheet's *.cs file it turned out I can access project's xlsx file this way:
var excel = (Excel.Application)this.Application;
var xlbook = (Excel.Workbook)excel.ActiveWorkbook;
var worksheets = xlbook.Worksheets;
var sheet = (Excel.Worksheet)worksheets["Sheet3"];
int row = 2;//1st row for column titles
while (!string.IsNullOrEmpty(((Excel.Range)sheet.Cells[row, 2]).Value))
{
var weight = ((Excel.Range)sheet.Cells[row, 3]).Value;
row++;
}
Some additional things about processing data from Excel sheet in c# code, I found out (maybe that's helpful for someone):
the .NET type for Excel Cell is Excel.Range (at least I didn't
find any other option)
when reading cell that is empty in Excel file, it's value on .NET side is null, not ""
values that seem to be strings on Excel side - can turn to be different types when loaded on c# side. I don't know if it's the best way, but I solved it like this:
var weight = (((Excel.Range)sheet.Cells[row, 3]).Value);
if (weight is double)
{
product.Weight = ((double)((Excel.Range)sheet.Cells[row, 3]).Value).ToString();
}
else if (weight is string)
{
product.Weight = ((Excel.Range)sheet.Cells[row, 3]).Value;
}

how to create and download excel document using asp.net

How to create and download excel document using asp.net ?
The purpose is to use xml, linq or whatever to send an excel document to a customer via a browser.
Edit : Use case
The customer load a gridview ( made with ajax framework ) in a browser, the gridview is directly linked to an sql database.
I put a button 'export to excel' to let customer save this gridview data on his computer ansd i would like to launch a clean download of an excel.
The solutions proposed here are not clean, like send an html document and change the header to excel document etc, i'm searching a simple solution on codeplex right now, i will let you know.
Starter kit
First i have downloaded the Open XML Format SDK 2.0.
It comes with 3 useful tools in :
C:\Program Files\Open XML Format SDK\V2.0\tools
DocumentReflector.exe wich auto
generate the c# to build a
spreadsheet from the code.
OpenXmlClassesExplorer.exe display
Ecma specification and the class
documentation (using an MSDN style
format).
OpenXmlDiff.exe graphically compare
two Open XML files and search for
errors.
I suggest anyone who begin to rename .xlsx to .zip, so you can see the XML files who drive our spreadsheet ( for the example our sheets are in "xl\worksheets" ).
The code
Disclaimer : I have stolen all the code from an MSDN technical article ;D
The following code use an *.xlsx template i made manually to be able to modify it.
Namespaces references
using System.IO;
using System.Xml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml;
// Database object
DataClassesDataContext db = new DataClassesDataContext();
// Make a copy of the template file.
File.Copy(#"C:\inetpub\wwwroot\project.Web\Clients\Handlers\oxml-tpl\livreurs.xlsx", #"C:\inetpub\wwwroot\project.Web\Clients\Handlers\oxml-tpl\generated.xlsx", true);
// Open the copied template workbook.
using (SpreadsheetDocument myWorkbook = SpreadsheetDocument.Open(#"C:\inetpub\wwwroot\project.Web\Clients\Handlers\oxml-tpl\generated.xlsx", true))
{
// Access the main Workbook part, which contains all references.
WorkbookPart workbookPart = myWorkbook.WorkbookPart;
// Get the first worksheet.
WorksheetPart worksheetPart = workbookPart.WorksheetParts.ElementAt(2);
// The SheetData object will contain all the data.
SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
// Begining Row pointer
int index = 2;
// Database results
var query = from t in db.Clients select t;
// For each item in the database, add a Row to SheetData.
foreach (var item in query)
{
// Cell related variable
string Nom = item.Nom;
// New Row
Row row = new Row();
row.RowIndex = (UInt32)index;
// New Cell
Cell cell = new Cell();
cell.DataType = CellValues.InlineString;
// Column A1, 2, 3 ... and so on
cell.CellReference = "A"+index;
// Create Text object
Text t = new Text();
t.Text = Nom;
// Append Text to InlineString object
InlineString inlineString = new InlineString();
inlineString.AppendChild(t);
// Append InlineString to Cell
cell.AppendChild(inlineString);
// Append Cell to Row
row.AppendChild(cell);
// Append Row to SheetData
sheetData.AppendChild(row);
// increase row pointer
index++;
}
// save
worksheetPart.Worksheet.Save();
}
I havent finished yet, my second job is to auto download the spreadsheet after modification.
Finally, i redirect the user to my generated spredsheet (from my aspx)
context.Response.Redirect("Oxml-tpl/generated.xlsx");
just set Response.ContentType = "application/vnd.ms-excel" and your page will rendered as an excel sheet on the clients browser
Sample code here
There are quite a few ways of handling this, depending on how extensive the Excel functionality is. Binoj's answer works if the Excel is just a spreadsheet and has no direct Excel functionality built in. The client can add functionality, concats, etc. These are "dumb" excel docs until the client does soemthing.
To create a more full featured Excel doc, you havve two basic choices that I can think of offhand.
Use either the office components (re: bad) to create an excel document, or a third party component, like SoftArtisan's ExcelWriter. Great component, but there is a cost.
Use a control on the page that allows export to Excel. Most vendors of ASSP.NET controls have this functionality on their grids.
Option #1 allows you pretty much all functionality of Excel. Option #2 is a bit more limited, at least in the controls I have tried.
Good article on how top export to excel from Erika Ehrli
http://blogs.msdn.com/erikaehrli/archive/2009/01/30/how-to-export-data-to-excel-from-an-asp-net-application-avoid-the-file-format-differ-prompt.aspx

Categories