Thursday, April 10, 2008

Deserializing non printable characters

Today I got on my desk to fix a problem with our import and export functionality. In an interface open to customers one of them had entered non printable characters in a string property which caused the import to fail if the item had been exported.

My first thought was that it seemed strange that the XmlSerializer of the .NET Framework didn't automatically encode string properties to proper XML. Looking at the XML file it was correct tho. Or, proper XML format at least. To be proper XML it seems you may not use control characters other than CR, LF and TAB.

XML Spec 1.0 says:
Char ::= #x9 #xA #xD [#x20-#xD7FF] [#xE000-#xFFFD] [#x10000-#x10FFFF]

Considering this it seems like the Serialize method that generated with XML should be the one complaining, but in this case the problem is reported by the Deserialize method. It throws an InvalidOperationException saying it encountered an invalid character in a call to ScanHexEntity.

With the help of Google I did however find a simple solution to the problem. Calling Deserialize with an XmlTextReader instead of a StringReader. Since the former has a constructor that take the latter as argument it has minimum inpact on the code too.

xmlSerializer.Deserialze(new XmlTextReader(sr));

The reason is that this XmlTextReader contructor initiates with the Normalization property set to false, while the XmlTextReader created under the hood from other calls to Deserialize is created with the property set to true.

A more sophisticated solution would be to base64 encode the string, but I'll stick with the simple solution. More than having very limited inpact and being a very quick solution it also has the benefit that old export files will work.

Friday, April 4, 2008

MSBuild Error MSB3171

Converting a solution from VS2003 to VS2008 today caused me almost an hour of headache. It seems that there is some bug with changing the manifest settings in managed C++.

The solution contains a number of C# projects and one Managed C++ project. I converted its debug configuration many month ago and today I was finally going to build it in release mode!

One problem in the conversion was that most assemblies, including the C++ project, used the attribute assembly:AssemblyKeyFileAttribute. With the new studio signing is invalidated by adding the manifesto if the key file is given with this attribute, which in turn causes a binding failure when trying to load the assembly in runtime.

I remembered solving it by setting the key file in the project settings when I converted the solution in debug mode earlier. Obviously I had failed to make the change in the release configuration at that point but it should be a quick fix.

At the first glance, though, I failed to find the box where it should be entered in the C++ project settings and thought I might have removed the manifesto instead. I tried setting "Embed manifesto" to "No" in Manifest Tool\Input and Output and kept the key file as an attribute. This made the MSB3171 appear, so I tried to also set "Generate Manifest" to "No" in Linker\Manifest File. No better. Looking for other things to change I f0und the place to add the key file in the project settings and decided to go with the initial idea.

I reverted my changes regarding manifesto, but the MSB3171 problem remained. I then reverted my project files using the source control system, but the problem still remaind. Outch! I restarted Visual Studio, but the problem refused to go away.

Next step was to ask Google. I found someone that had a similar experience, but I found no answer. Others trying to reproduce his problem failed and the common conclusion was that there was something wrong with his Studio.

My next move did how ever solve the problem. I closed the Studio. I reverted all files I had changed this morning, and deleted all intermediate files in the solution that had been changed today. That is, all bin and obj directories, .ncb files, .suo files and all other files that the Studio generates. Now when I started the Studio again I got the same error as first thing in the morning, I then added the key file on the correct place in the settings for the Managed C++ projects Release configuration and now it all works!