EPPlus edited XLSM files show Error in Excel - c#

I use the EPPlus library to batch edit some existing XLSM files. Inside the files I replace a line of VBA code and that's it. Everything works nice, if I edit the same line in the Excel code editor by hand.
When I open some of the files with Excel 2013 (15.0.4989.1000), the following error message is shown.
We found a problem with some content in 'test.xlsm'. Do you want us to
recover as much as we can? If you trust the source of this workbook,
click Yes.
If I click yes, the repair report shows the following entry. But the message is somewhat too generic to help me further.
Removed Records: Named range from /xl/workbook.xml-Part (Arbeitsmappe)
This is my C# code, which edits the XLSM file. Can I update my code or do I have to update the XLSM-file before editing it?
static void PatchVba(string filePath, string oldCode, string newCode)
{
var wbFileInfo = new FileInfo(filePath);
using (var package = new ExcelPackage(wbFileInfo, false))
{
foreach (var m in package.Workbook.VbaProject.Modules)
{
if (m.Code.Contains(oldCode))
{
m.Code = m.Code.Replace(oldCode, newCode);
Console.WriteLine("VBA Patched in \"{0}\"", filePath);
}
}
try
{
package.SaveAs(wbFileInfo);
}
catch
{
Console.WriteLine("Could not save patched file \"{0}\".", filePath);
}
}
}

I found out what the problem is. In the edited XLSM-file, a range name is used multiple times with overlapping scope. I was too focused on my C# code to find the root cause.
So removing the named ranges solves the issue. But it would still be interesting to know, why I can edit it without problems using Excel, but not by using EPPlus.

Related

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.

Create Excel with Drop down using Open XML

I am creating an excel with drop down values using Open XML (DocumentFormat.OpenXML). There are no errors in the code and excel gets created. But I get couple of errors while opening the excel. Excel gets opened with data correctly if I click OK to the errors and go ahead. It looks like the problem is due to the addition of namespace in order to have the dropdown values.
Question is, Is there any way to get rid of the error?
Error 1:
We found a problem with some content in 'sample.xlsx'. Do you want us
to try to recover as much as we can? If you trust the source of this
workbook, click Yes.
Error 2:
Errors were detected in file 'Sample.xlsx'
Repaired Records: Cell information
from /xl/worksheets/sheet2.xml part
Repaired Records: Cell information from
/xl/worksheets/sheet3.xml part
C# Namespace addition for creating excel:
worksheet1 = new Worksheet() { MCAttributes = new MarkupCompatibilityAttributes() { Ignorable = "x14ac" } };
worksheet1.AddNamespaceDeclaration("x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");

Receiving message of issue with content in Excel File

I am currently building an Excel file by hand using OpenXml. I'm in the process of adding the sheets, however, I have come across an issue. I have a loop that adds the names of each sheet in but once it runs and I try to open the file, I get the following message:
"We found a problem with some content in 'FileName.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 think the issue might be due that I am adding in the name of each sheet using a string variable. When I take it out and add something else, it works. Below is my code where I am looping through and adding my sheets.
//Technology Areas
foreach (DataRow dr in techAreaDS.Rows)
{
var data = dr["TechAreaName"].ToString().Split('-');
var techArea = data[2].TrimStart();
var techAreaSheet = new Sheet { Id = workbookPart.GetIdOfPart(worksheetPart),
SheetId = sheetId, Name = techArea };
sheets.Append(techAreaSheet);
sheetId++;
}
I've seen people mention it is an issue with cells having strings that can be converted into strings, but in this case, the string will always be a string. Any help would be appreciated.
EDIT: I've figured out the problem. The issue is the Name property has a Max Length of 31. One of my items has a 42 length, hence the error. I did find a cool set of code to validate my OpenXml. Link.
UPDATE:
Oddly enough, someone thinks this question was about finding some code to help validate what I was doing. It was not... The question is clear: why was I receiving an error when trying to name sheets. I was not asking for validation code, though I found some.
I do ask that if you wish to help, please read the question versus assume what I was asking, and if you don't know what I wish to have answered, ask...
In order to find out the issue(s) causing this error, you need to validate the generated document.
Besides using the built in validation method as described here, which doesn't show you all issues as I found out, I suggest that you download and install Microsoft's Open XML SDK 2.5 for Microsoft Office.
It contains Microsoft's Open XML SDK 2.5 Productivity Tool, which is very helpful here:
Create a copy of the damaged XLSX file, and apply the fixes as Microsoft Excel is suggesting (suppose you have the files FileName_corrupt.xlsx and FileName_fixed.xlsx
Then, run Microsoft's Open XML SDK 2.5 Productivity Tool, open FileName_corrupt.xlsx, select "Compare Files" and specify the 2nd file FileName_fixed.xlsx. This allows you to compare the XML structure of both files.
Let Microsoft's Open XML SDK 2.5 Productivity Tool generate C# code from both files: Open them first, then right-click on the root level and select "Reflect Code". This will create C# code which allows you to generate the same file. Save both C# code versions (i.e. FileName_corrupt.cs and FileName_fixed.cs)
Now you can compare the differences via Visual Studio: Either use
devenv.exe /diff FileName_corrupt.cs FileName_fixed.cs
to compare them, or use the batch file I've created to launch the VS compare - this is a hidden feature in Visual Studio, it allows to compare 2 local files being not part of TFS.
This way you should be able to work out the differences and allow you to fix your code.
NOTE: For a first validation, I do suggest to use the validation code. Only if it still fails, use the steps above. For validation you can use
public static string ValidateOpenXmlDocument(OpenXmlPackage pXmlDoc, bool throwExceptionOnValidationFail=false)
{
using (var docToValidate = pXmlDoc)
{
var validator = new DocumentFormat.OpenXml.Validation.OpenXmlValidator();
var validationErrors = validator.Validate(docToValidate).ToList();
var errors = new System.Text.StringBuilder();
if (validationErrors.Any())
{
var errorMessage = string.Format("ValidateOpenXmlDocument: {0} validation error(s) with document", validationErrors.Count);
errors.AppendLine(errorMessage);
errors.AppendLine();
}
foreach (var error in validationErrors)
{
errors.AppendLine("Description: " + error.Description);
errors.AppendLine("ErrorType: " + error.ErrorType);
errors.AppendLine("Node: " + error.Node);
errors.AppendLine("Path: " + error.Path.XPath);
errors.AppendLine("Part: " + error.Part.Uri);
if (error.RelatedNode != null)
{
errors.AppendLine("Related Node: " + error.RelatedNode);
errors.AppendLine("Related Node Inner Text: " + error.RelatedNode.InnerText);
}
errors.AppendLine();
errors.AppendLine("==============================");
errors.AppendLine();
}
if (validationErrors.Any() && throwExceptionOnValidationFail)
{
throw new Exception(errors.ToString());
}
if (errors.Length > 0)
{
System.Diagnostics.Debug.WriteLine(errors.ToString());
}
return errors.ToString();
}
along with
public static void ValidateExcelDocument(string fileName)
{
using (var xlsx = SpreadsheetDocument.Open(fileName, true))
{
ValidateOpenXmlDocument(xlsx);
}
}
With a slight modification, you can easily use the code above for Microsoft Word validation too:
public static void ValidateWordDocument(string fileName)
{
using (var docx = WordprocessingDocument.Open(fileName, true))
{
ValidateOpenXmlDocument(docx);
}
}
I've figured out the problem. The issue is the Name property has a Max Length of 31 characters. The text I'm trying to use sometimes exceeds that limit (one has 42 characters). I also found a pretty cool set of code to validate my Open Xml to find out what the specific issue is. Link

Multiple pivottable creation using EPPlus

Im just starting to use EPPLus Lib to create "complex" workbooks via C#, and i just ran into some trouble while trying to create two pivot tables.
The first one creates fine, but when i try to create the second one it doesnt throw any exceptions but when i try to open the worknook using excel it says
"Excel found unreadable content in 'myworkbook.xlsx'. Do you want to
recover the contents of this workbook? If you trust the source of this
workbook, clickYes"
And when i press 'yes':
Repair log ->
Removed Feature: PivotTable report from /xl/pivotTables/pivotTable2.xml part (PivotTable > view) Removed
Records: Workbook properties from /xl/workbook.xml part (Workbook)
Repaired Records: Workbook properties from /xl/workbook.xml part
(Workbook)
Here's the code that i build:
CreatePivotTable("Pivot1", "Pivot1", rng1);
CreatePivotTable("Pivot2", "Pivot2", rng2);
public void CreatePivotTable(string pivotSheet, string pivotName, ExcelRangeBase srcRange)
{
if (m_wb.Worksheets[pivotSheet] != null)
m_wb.Worksheets.Delete(pivotSheet);
var ws = m_wb.Worksheets.Add(pivotSheet);
var pivot = ws.PivotTables.Add(ws.Cells["A1"], srcRange, pivotName);
}
Any ideas?
Thanks!
What was wrong and i didnt put it in my question was that i was reopening the workbook on step before, like this:
CreatePivotTable("Pivot1", "Pivot1", rng1);
Save();
CreatePivotTable("Pivot2", "Pivot2", rng2);
private void Save()
{
m_writer.Save();
m_writer.OpenWorkbook ();
}
And since the save method of epplus closes the workbook, the program lost some sort of reference or just got lost with some info.
In short, to use epplus correctly, you should write everything u need before saving and closing the workbook, its not good to reopen.
Thank you.

Programmatically reading VS .coveragexml file in C#

So I have some code that can read the methods out of a .coverage file...
using (CoverageInfo info = CoverageInfo.CreateFromFile(this.myCoverageFile))
{
CoverageDS ds = info.BuildDataSet();
foreach (ICoverageModule coverageModule in info.Modules)
{
CodeModule currentModule = new CodeModule(coverageModule.Name);
byte[] coverageBuffer = coverageModule.GetCoverageBuffer(null);
using (ISymbolReader reader = coverageModule.Symbols.CreateReader())
{
Method currentMethod;
while (reader.GetNextMethod(out currentMethod, coverageBuffer))
{
if (currentMethod != null)
{
currentModule.Methods.Add(currentMethod);
}
}
}
returnModules.Add(currentModule);
}
}
... but I want to be able to read .coverage files that have been exported to xml too. The reason for this is that .coverage files require the source dlls be in the exact location they were when code coverage was measured, which doesn't work for me.
When I try to load a coveragexml file using CreateFromFile(string) I get the following exception.
Microsoft.VisualStudio.Coverage.Analysis.InvalidCoverageFileException
was unhandled Message=Coverage file
"unittestcoverage.coveragexml" is
invalid or corrupt.
The coveragexml file opens in Visual Studio just fine, so I don't believe there's any issue with the file's format.
I know that CoverageDS can import an xml file, but the API is less than intuitive and the only example I can find of its use is...
using(CoverageInfo info = CoverageInfo.CreateFromFile(fileString))
{
CoverageDS data = info.BuildDataSet();
data.ExportXml(xmlFile);
}
...which tells me nothing about how to actually read the coverage data from that file.
Does someone know how to process code coverage data from a .coveragexml file?
Probably the best introduction to manipulating code coverage information programmatically is available here and also in the linked ms_joc blog.
I'm pretty sure you can use 'CreateInfoFromFile' with either the .coverage file or the XML file you exported in the sample above.
UPDATE:
CreateInfoFromFile throws an exception if the coveragexml is passed as the argument. Here is an alternative:
CoverageDS dataSet = new CoverageDS();
dataSet.ImportXml(#"c:\temp\test.coveragexml");
foreach (CoverageDSPriv.ModuleRow module in dataSet.Module)
{
Console.WriteLine(String.Format("{0} Covered: {1} Not Covered: {2}", module.ModuleName, module.LinesCovered, module.LinesNotCovered));
}
Have you tried the CoverageDS.ReadXml(fileName_string) method?

Categories