XmlSerializer does not use XmlSerializers.dll created by sgen

In my Visual Studio 2010 project, I use the following Post-Build command line to use sgen to create XmlSerializers.dll.

Build Event:

"$(ProgramFiles)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sgen.exe" /a:"$(TargetPath)" /c:/keyfile:"c:\myproject\mykey.snk" /f 

My project has a strong name, so use the same key for the strong name "XmlSerializers.dll". VS creates XmlSerializers.dll in the output folder.

However, I noticed that using ProcessMonitor.NET it still calls CSC.exe at runtime. I came across this post where the user had a similar problem and resolved using the XmlSerializer (Type) constructor.

I used the same technique in my code, but it still calls csc.exe:

 var fs = new FileStream(SettingsFilePath, FileMode.Open); try { var serializer = new XmlSerializer(typeof(AppSettings)); settings = (AppSettings)serializer.Deserialize(fs); } finally { fs.Close(); } 

The reason I need to use precompiled XML serialization is because of performance, and I also occasionally see csc.exe errors when Windows shuts down. My application saves data when I close the form at shutdown, as Windows does not allow the start of a new process during the shutdown sequence. I saw recommendations to get around this by precompiling XML serialization.

Any suggestions on why XmlSerializer is not using XmlSerializers.dll created by sgen?

Thanks.

+7
source share
3 answers

Perhaps the problem is in another target platform: by default sgen uses "Any CPU" (MSIL), if the assembly containing the deserialized or serialized type is compiled for x86 o x64, it will not load .XmlSerializers.dll

In general, I looked at the .NET code that loads the serialization assemblies - here is some kind of code that reproduces the same behavior as unit testing:

 /// <summary>Generates an identifier for the assembly of a specified type</summary> /// <remarks>Code copied from the .NET serialization classes - to emulate the same bahavior</remarks> /// <param name="type">The type</param> /// <returns>String identifying the type assembly</returns> static string GenerateAssemblyId(Type type) { Module[] modules = type.Assembly.GetModules(); ArrayList list = new ArrayList(); for (int i = 0; i < modules.Length; i++) { list.Add(modules[i].ModuleVersionId.ToString()); } list.Sort(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.Count; i++) { sb.Append(list[i].ToString()); sb.Append(","); } return sb.ToString(); } // GenerateAssemblyId /// <summary>Verifies that the serialization assembly for the specified type can be loaded</summary> /// <remarks>Code copied from the .NET serialization classes - to emulate the same behavior and tests</remarks> /// <param name="type">The type</param> static void AssertCanLoadXmlSerializers(Type type) { if (type == null) throw new ArgumentNullException("type"); Assembly serializerAssembly = null; // Create the name of the XML serilizers assembly from the type one AssemblyName name = type.Assembly.GetName(true); name.Name = name.Name + ".XmlSerializers"; name.CodeBase = null; name.CultureInfo = CultureInfo.InvariantCulture; try { serializerAssembly = Assembly.Load(name); } catch (Exception e) { Assert.Fail("Unable to load XML serialization assembly for type '{0}': {1}", type.FullName, e.Message); } object[] attrs = serializerAssembly.GetCustomAttributes(typeof(XmlSerializerVersionAttribute), false); if (attrs == null || attrs.Length == 0) { Assert.Fail( "Unable to use XML serialization assembly '{1}' for type '{0}': it does not contain XmlSerializerVersionAttribute", type.FullName, serializerAssembly.FullName ); } if (attrs.Length > 1) { Assert.Fail( "Unable to use XML serialization assembly '{1}' for type '{0}': it contains multiple XmlSerializerVersionAttribute", type.FullName, serializerAssembly.FullName ); } XmlSerializerVersionAttribute assemblyInfo = (XmlSerializerVersionAttribute)attrs[0]; string assemblyId = GenerateAssemblyId(type); if (assemblyInfo.ParentAssemblyId != assemblyId) { Assert.Fail( "Unable to use XML serialization assembly '{1}' for type '{0}': it does not match assembly id '{2}'", type.FullName, serializerAssembly.FullName, assemblyId ); } } // AssertCanLoadXmlSerializers 

just call AssertCanLoadXmlSerializers() , passing the type what you need to serialize / deserialize. If serialization assemblies do not load, you may well understand why from the error messages.

I added it to our unit testing, so that I can be sure that the serialization builds are in order.

+4
source

Have you tried running ngen.exe in the generated dll?

Launch

 ngen.exe install myproject.XmlSerializers.dll 

installs its own DLL image in the image cache, which should be used at runtime, and not to invoke the JIT compiler.

0
source

Are you sure the serialization assembly is correctly signed? Usually you need to avoid quotes. See here for more details.

You can also check for matching matches. If you change the original assembly after assembling the serialization assembly, the identifiers no longer match and the serialization assembly will not be used. See here for more details.

If all this is correct: turn off Tools β†’ Options β†’ Debugging β†’ β€œInclude only my code” and turn on Debug β†’ Excpetions β†’ Exceptions for the usual Runtime language β†’ Thrown. Then debug the application to the point at which serialization is performed. The first exception exception will indicate why the serialization assembly cannot be used.

0
source

All Articles