I have a C# app that exports to Excel using ClosedXML. It works fine but just ran into an issue where when i hit the :
var ms = new MemoryStream();
workbook.SaveAs(ms);
I get an exception:
' ', hexadecimal value 0x0B, is an invalid character
Its definitely data related because it I look at certain data it works fine but other data it causes this issue.
how can i figure out which character is causing the issue? Also, once I figure that out, what is the best way of finding where this character is within my data?
Since ClosedXML is an open source project, the simplest way of tracking the error down would be building it from the source *, and then running your code against the library in debug mode.
Once you see the full stack trace, you should be able to identify the spot from which the error is coming. Good chances are that it is a bug in the way the ClosedXML project uses Microsoft XML libraries, because the error that you mentioned is reported by a library outside the ClosedXML project.
* I downloaded the project, and tried building it. Everything in the
closedxml-79843.zip
package builds correctly.Since you have invalid characters in the data / strings you put into the ClosedXML sheet, you have to find them and get them out.
The simplest solution is to add
to all your strings to get rid of the vertical tabs and replace them with spaces.
Since ClosedXML doesn't prevent you from using the 0x0B character in values, you'll either have to scrub your data of it yourself (as suggested by @Raidri), or you could force and exception, or do a string replace when the value is set. I've created a sample program below which uses Castle's Dynamic Proxy to wrap the
IXLWorksheet
andIXLCell
interfaces. Firstly, we proxy theIXLWorksheet
values (which returned from adding a new worksheet as in the example below, or by indexing an existing worksheet). This needs to be done manually via a method call; everything else from then on is set up. When accessing cells (via theCell
methods, or theActiveCell
property) a proxiedIXLCell
value is returned which checks the data being set via theValue
property and theSetValue
method. The check is done in theValidateMethodInterceptor
as per the comments. This whole mechanism can be left in your codebase and turned on/off via a switch in theProgram.Proxy
method if you so desire.As a further alternative, the package EPPlus (which has similar functionality to ClosedXML) doesn't crash when confronted with the VT character. Instead it replaces it with the value
_x00B_
. Perhaps a switch would be more beneficial?