XmlSerializer n’utilise pas XmlSerializers.dll créé par sgen

Dans mon projet Visual Studio 2010, j’utilise la ligne de commande suivante après l’événement pour utiliser sgen pour créer XmlSerializers.dll.

Evénement post-construction:

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

Mon projet est nommé fort, utilisez donc la même clé pour nommer fort “XmlSerializers.dll”. VS crée le XmlSerializers.dll dans le dossier de sortie.

Cependant, j’ai remarqué qu’en utilisant ProcessMonitor, .NET appelle toujours CSC.exe au moment de l’exécution. Je suis tombé sur ce post , où l’utilisateur avait un problème similaire et résolu en utilisant le constructeur XmlSerializer (Type).

J’ai utilisé la même technique dans mon code mais il appelle toujours csc.exe:

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

La raison pour laquelle j’ai besoin d’utiliser la sérialisation XML précompilée, à cause des performances et aussi, j’ai parfois vu des erreurs csc.exe lors de l’arrêt de Windows. Mon application enregistre les données lors de la fermeture du formulaire lors de l’arrêt, car Windows n’autorisera pas le lancement d’un nouveau processus lors de la séquence d’arrêt. J’ai vu des recommandations pour contourner ce problème en précompilant la sérialisation XML.

Des suggestions sur la raison pour laquelle XmlSerializer n’utilise pas XmlSerializers.dll créé par sgen?

Merci.

Le problème est peut-être lié à une plate-forme cible différente: par défaut, sgen utilise ‘Any CPU’ (MSIL), si l’assembly contenant le type à désérialiser ou sérialiser est compilé pour x86 ou x64, il ne chargera pas le .XmlSerializers.dll

Plus généralement, j’ai jeté un œil au code .NET qui charge les assemblys de sérialisation – voici un code reproduisant le même comportement qu’un test unitaire:

 /// Generates an identifier for the assembly of a specified type /// Code copied from the .NET serialization classes - to emulate the same bahavior /// The type /// Ssortingng identifying the type's assembly static ssortingng 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 /// Verifies that the serialization assembly for the specified type can be loaded /// Code copied from the .NET serialization classes - to emulate the same behavior and tests /// The type 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.GetCustomAtsortingbutes(typeof(XmlSerializerVersionAtsortingbute), false); if (attrs == null || attrs.Length == 0) { Assert.Fail( "Unable to use XML serialization assembly '{1}' for type '{0}': it does not contain XmlSerializerVersionAtsortingbute", type.FullName, serializerAssembly.FullName ); } if (attrs.Length > 1) { Assert.Fail( "Unable to use XML serialization assembly '{1}' for type '{0}': it contains multiple XmlSerializerVersionAtsortingbute", type.FullName, serializerAssembly.FullName ); } XmlSerializerVersionAtsortingbute assemblyInfo = (XmlSerializerVersionAtsortingbute)attrs[0]; ssortingng 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 

Il suffit d’appeler AssertCanLoadXmlSerializers() transmettant le type qui doit être sérialisé / désérialisé. Si les ensembles de sérialisation ne se chargent pas, vous pouvez avoir une assez bonne idée du pourquoi des messages d’erreur.

Je l’ai ajouté à nos tests unitaires afin que je puisse être raisonnablement sûr que les assemblys de sérialisation fonctionnent correctement.

Avez-vous essayé d’exécuter ngen.exe sur la dll générée?

Fonctionnement

 ngen.exe install myproject.XmlSerializers.dll 

installera une image native de la dll dans le cache d’images, qui devrait être utilisée à l’exécution plutôt que d’appeler le compilateur JIT.

Êtes-vous sûr que l’assemblage de sérialisation est correctement signé? Habituellement, vous devez échapper aux guillemets. Voir ici pour plus d’informations.

Vous pouvez également vérifier si les identifiants correspondent. Si vous modifiez l’assembly source après avoir construit l’assemblage de sérialisation, les ID ne correspondent plus et l’assembly de sérialisation ne sera pas utilisé. Voir ici pour plus d’informations.

Si tout cela est correct: Désactiver Outils -> Options -> Débogage -> “Activer uniquement mon code” et activer le débogage -> Excpetions -> Exceptions du langage commun -> Lancées. Déboguez ensuite votre application au point où la sérialisation est effectuée. Une exception de première chance sera émise indiquant pourquoi l’assemblage de sérialisation ne peut pas être utilisé.