In my Visual Studio 2010 project, I use following Post-Build event command line to use sgen to create XmlSerializers.dll.
Post 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 is strong named, so use the same key to strong name the "XmlSerializers.dll". VS creates the XmlSerializers.dll in output folder.
However, I have noticed using ProcessMonitor, .NET still invoke CSC.exe at runtime. I came accross this post, where the user had similar issue and resolved by using XmlSerializer(Type) constructor.
I used same technique in my code but it still invoke 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 serialisation, because of performance and also I have seen sometimes csc.exe erros on Windows shutdown. My application saves data when Form close, during shutdown, it fails because Windows will not allow a new process to start during the shutdown sequence. I have seen recommendations to get around this by precompiling XML serialisation.
Any suggestions about why XmlSerializer not using XmlSerializers.dll created by sgen?
Thanks.
Possiby the problem is different target platform: by default sgen
uses 'Any CPU' (MSIL), if the assembly containing the type to be deserialized or serialized is compiled for x86 o x64, it won't load the .XmlSerializers.dll
More in general, I had a look at the .NET code that load the serialization assemblies - here is some code that reproduce the same behavior as a 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's 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's 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
simply call AssertCanLoadXmlSerializers()
passing the type than needs to be serialized/deserialized. If the serialization assemblies do not load you can have a fairly good idea of why from the error messages.
I added it to our unit testing, so that I can be reasonably sure that the serialization assemblies are OK.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With