XmlSerializer donnant FileNotFoundException au constructeur

347

Une application avec laquelle je travaille échoue lorsque j'essaie de sérialiser des types.

Une déclaration comme

XmlSerializer lizer = new XmlSerializer(typeof(MyType));

produit:

System.IO.FileNotFoundException occurred
  Message="Could not load file or assembly '[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
  Source="mscorlib"
  FileName="[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
  FusionLog=""
  StackTrace:
       at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
       at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)

Je ne définis aucun sérialiseur spécial pour ma classe.

Comment puis-je résoudre ce problème?

Irwin
la source
5
OK, donc cette question est juste ma version C # d'une question VB déjà posée: stackoverflow.com/questions/294659/… Merci les gars.
Irwin
1
Six ans plus tard, la réponse de @VladV est la solution la plus simple et la moins préjudiciable. Modifiez simplement le Generate serialization assemblymenu déroulant sur "On", au lieu de "Auto".
Heliac
@Heliac: Je ne suis pas d'accord. Ça ne marche pas toujours. Veuillez voir le commentaire de Benoit Blanchon à la réponse de Vlad. La réponse la plus simple pour moi est de ne pas utiliser String.Collection dans les fichiers de configuration. Au lieu de cela, j'utilise: string [] items = Settings.Default.StringofNewlineDelimitedItems.Split (new [] {Environment.NewLine});
Andrew Dennison

Réponses:

388

Croyez-le ou non, c'est un comportement normal. Une exception est levée mais gérée par XmlSerializer, donc si vous l'ignorez, tout devrait bien continuer.

J'ai trouvé cela très ennuyeux, et il y a eu de nombreuses plaintes à ce sujet si vous recherchez un peu, mais d'après ce que j'ai lu, Microsoft n'a pas l'intention de faire quoi que ce soit à ce sujet.

Vous pouvez éviter d'obtenir des fenêtres contextuelles d'exception tout le temps lors du débogage si vous désactivez les exceptions de première chance pour cette exception spécifique. Dans Visual Studio, accédez à Debug -> Exceptions (ou appuyez sur Ctrl+ Alt+ E), Common Language Runtime Exceptions -> System.IO -> System.IO.FileNotFoundException .

Vous pouvez trouver des informations sur un autre moyen de le contourner dans l' exception de blog C # XmlSerializer FileNotFound (qui traite de l'outil XmlSerializerPreCompiler de Chris Sells ).

Martin Sherburn
la source
162
Une des façons possibles de se débarrasser de ce problème est de cocher l'option "Juste mon code" dans Outils -> Options -> Débogage -> Options générales.
Frédéric
26
@Frederic: Ce commentaire est génial! Je suis assis ici avec un "WTF !?" expression sur mon visage, en essayant de traquer cette fausse exception, et je trouve cette question, avec réponse (c'est la faute de Microsoft, quoi d'autre est nouveau?), mais je ne voulais pas désactiver la gestion des exceptions, car j'en aurais peut-être besoin pour mon code. A +!
Kumba
27
Je pense que la suggestion de Hans ci-dessous est plus valable - utilisez un appel de méthode différent qui ne produit pas du tout cette exception: XmlSerializer serializer = XmlSerializer.FromTypes (new [] {typeof (MyType)}) [0];
lumineux
3
Le problème est que cela échoue à mon test, donc je ne peux pas simplement "ignorer" l'exception
Csaba Toth
16
Je suis désolé, mais c'est une terrible suggestion. FileNotFoundException est l'une des plus courantes, selon mon expérience, et la désactivation de ce rapport d'exception demande simplement des problèmes un jour à l'avenir. Mieux vaut activer «Just My Code» ou activer la création des assemblys de sérialisation décrits ci-dessous.
Quarkly
104

Comme Martin Sherburn l'a dit, c'est un comportement normal. Le constructeur de XmlSerializer essaie d'abord de trouver un assembly nommé [YourAssembly] .XmlSerializers.dll qui doit contenir la classe générée pour la sérialisation de votre type. Puisqu'une telle DLL n'a pas encore été générée (elles ne le sont pas par défaut), une FileNotFoundException est levée. Lorsque cela se produit, le constructeur de XmlSerializer intercepte cette exception et la DLL est générée automatiquement au moment de l'exécution par le constructeur de XmlSerializer (cela se fait en générant des fichiers source C # dans le répertoire% temp% de votre ordinateur, puis en les compilant à l'aide du compilateur C #). Les constructions supplémentaires d'un XmlSerializer pour le même type utiliseront simplement la DLL déjà générée.

MISE À JOUR: À partir de .NET 4.5, XmlSerializern'effectue plus la génération de code ni la compilation avec le compilateur C # afin de créer un assembly sérialiseur au moment de l'exécution, sauf si explicitement contraint à définir un paramètre de fichier de configuration ( useLegacySerializerGeneration ). Cette modification supprime la dépendance csc.exeet améliore les performances de démarrage. Source: Lisezmoi .NET Framework 4.5 , section 1.3.8.1.

L'exception est gérée par le constructeur de XmlSerializer. Il n'est pas nécessaire de faire quoi que ce soit vous-même, vous pouvez simplement cliquer sur «Continuer» (F5) pour continuer à exécuter votre programme et tout ira bien. Si vous êtes gêné par les exceptions arrêtant l'exécution de votre programme et faisant apparaître un assistant d'exception, vous avez soit 'Just My Code' désactivé, soit vous avez défini FileNotFoundException pour interrompre l'exécution lorsqu'il est lancé, au lieu de quand 'User- non géré ».

Pour activer «Just My Code», accédez à Outils >> Options >> Débogage >> Général >> Activer Just My Code. Pour désactiver la rupture d'exécution lorsque FileNotFound est levé, accédez à Debug >> Exceptions >> Find >> entrez 'FileNotFoundException' >> décochez la case 'Thrown' de System.IO.FileNotFoundException.

Allon Guralnek
la source
+1 pour la mise à jour: cela explique le comportement différent lors du débogage des cas de test
mbx
3
Votre mise à jour suggère que cette exception ne devrait pas se produire dans .NET 4.5, mais je la vois toujours.
Timbo
@Timbo: Je ne vois pas pourquoi vous n'obtiendrez pas cette exception avec .NET 4.5. Il recherche toujours un fichier, et si le fichier est manquant, un FileNotFoundExceptionsera lancé. La différence n'est pas dans la façon dont l'existence de l'assembly est vérifiée, mais dans la façon de le générer une fois qu'il est déterminé qu'il est manquant. Avant, il utilisait la génération de code C # textuel avec un appel au compilateur C # pour créer l'IL. À partir de .NET 4.5, il émet IL directement, sans utiliser de compilateur.
Allon Guralnek
1
Je souhaite juste que MS implémente cela comme si (File.Exists (...)) {Load} else {Fallback} au lieu d'essayer {Load} catch {Fallback}. Le contrôle de flux basé sur des exceptions sent mauvais et rend mon expérience de débogage plus difficile et plus fragile que nécessaire.
Timbo
1
@Timbo: Un simple File.Exists()peut ne pas être suffisant. La localisation d'un assembly n'est pas une affaire simple, le runtime regarde à plusieurs endroits et je crois que le comportement change en fonction de l'environnement (application console vs hébergée dans IIS, etc.). Je suppose que ce qui aurait dû être mis en œuvre était un TryLoadAssembly()ou quelque chose de similaire.
Allon Guralnek
63

Dans les propriétés du projet Visual Studio (page "Build", si je me souviens bien), il y a une option disant "générer un assemblage de sérialisation". Essayez de l'activer pour un projet qui génère [Assemblage contenant de MyType] .

VladV
la source
4
Voir également stackoverflow.com/a/8798289/1164966 si l'assembly de sérialisation n'est toujours pas généré par Visual Studio.
Benoit Blanchon
Meilleure réponse, la plus claire et la plus succincte! J'aimerais pouvoir voter à nouveau aussi!
John Zabroski
59

Il existe une solution pour cela. Si tu utilises

XmlSerializer lizer = XmlSerializer.FromTypes(new[] { typeof(MyType) })[0];

il devrait éviter cette exception. Cela a fonctionné pour moi.

AVERTISSEMENT: ne pas utiliser plusieurs fois, ou vous aurez une fuite de mémoire

Vous perdrez de la mémoire comme un fou si vous utilisez cette méthode pour créer des instances de XmlSerializer même type!

En effet, cette méthode contourne la mise en cache intégrée à condition que le XmlSerializer(type)etXmlSerializer(type, defaultNameSpace) constructeurs (tous les autres constructeurs contournent également le cache).

Si vous utilisez une méthode pour créer un XmlSerializer qui n'est pas via ces deux constructeurs, vous devez implémenter votre propre mise en cache ou vous aurez une mémoire d'hémorragie.

quadfinité
la source
44
AVERTISSEMENT: vous fuierez la mémoire comme un fou si vous utilisez cette méthode pour créer plusieurs fois des instances du XmlSerializermême type! Cela est dû au fait que cette méthode contourne la mise en cache intégrée à condition que les constructeurs XmlSerializer(type)et XmlSerializer(type, defaultNameSpace)(tous les autres constructeurs contournent également le cache). Si vous utilisez une méthode pour créer un XmlSerializerqui ne passe pas par ces deux constructeurs, vous devez implémenter votre propre mise en cache ou vous aurez une mémoire d'hémorragie.
Allon Guralnek
4
@AllonGuralnek Eh bien, je serai damné ... vous avez absolument raison; creuser davantage via Reflector montre que bien qu'il vérifie le cache, il le fait après avoir généré l'assembly de sérialisation! Wtf?!?
JerKimball
4
Il s'avère que c'est un bug connu: weblogs.asp.net/cschittko/archive/2005/01/14/353435.aspx
JerKimball
3
@ Jerkimball: Cette page ne ment pas réellement. Comme vous l'avez découvert, FromTypessemble remplir le cache. Donc, cela devrait être un moyen valide de réchauffer un XmlSerializercache vide dans une instruction (comme le suggère l'article), mais un très mauvais moyen d'en récupérer quoi que ce soit (ne doit être fait que via les constructeurs les plus simples). En tout cas, je ne savais pas que c'était un bug, j'ai toujours pensé que tout ce qui fuit est censé fuir (comme les XmlSerializerconstructeurs les plus avancés ). Je n'aurais même pas pensé à utiliser FromTypes()car vous pouvez le faire types.Select(t => new XmlSerializer(t)).
Allon Guralnek
2
@AllonGuralnek L'aspect non probant de l'utilisation FromTypesa son attrait - même si les exceptions levées sont toutes interceptées, c'est une opération coûteuse; l'approche «cache à votre façon» semble être la seule solution de contournement, car le seul correctif officiellement pris en charge semble être dans un assemblage Web obscur. (modifier: franchement, je suis tout pour tout porter sur les contrats de données :))
JerKimball
22

J'ai rencontré ce problème exact et je n'ai pu le contourner par aucune des solutions mentionnées.

Puis j'ai finalement trouvé une solution. Il semble que le sérialiseur ait besoin non seulement du type, mais également des types imbriqués. Changer ceci:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

Pour ça:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(T).GetNestedTypes());

Correction du problème pour moi. Plus d'exceptions ou quoi que ce soit.

Glacial
la source
8
Cela a fonctionné pour moi. En utilisant .Net4.0, le format estvar xmlSerializer = new XmlSerializer(typeof(T), typeof(T).GetNestedTypes());
user3161729
1
Cela a également fonctionné pour moi. Mais cela ne semble nécessaire que lors de la sérialisation, pas lors de la désérialisation. Peut-être que cela a du sens, peut-être que non.
SteveCinq
2
Cela produit également une fuite de mémoire, s'il est exécuté plusieurs fois.
Volodymyr Kotylo
9

Ma solution est d'aller directement à la réflexion pour créer le sérialiseur. Cela contourne l'étrange chargement de fichier qui provoque l'exception. J'ai empaqueté ceci dans une fonction d'aide qui s'occupe également de la mise en cache du sérialiseur.

private static readonly Dictionary<Type,XmlSerializer> _xmlSerializerCache = new Dictionary<Type, XmlSerializer>();

public static XmlSerializer CreateDefaultXmlSerializer(Type type) 
{
    XmlSerializer serializer;
    if (_xmlSerializerCache.TryGetValue(type, out serializer))
    {
        return serializer;
    }
    else
    {
        var importer = new XmlReflectionImporter();
        var mapping = importer.ImportTypeMapping(type, null, null);
        serializer = new XmlSerializer(mapping);
        return _xmlSerializerCache[type] = serializer;
    }
}
d - b
la source
2 problèmes ici - premièrement, votre code n'est pas compatible avec les threads, et deuxièmement (plus important encore), vous essayez de reproduire ce que le runtime .net fait déjà (en fonction du ctor que vous utilisez). c'est-à-dire qu'il n'y a pas besoin de ce code
Dave Black
@DaveBlack: Oui, la réponse de quadfinity avec la mise en cache d'un ConcurrentDictionary serait meilleure
d - b
@db Mon deuxième point était que la mise en cache n'est même pas nécessaire - tant que vous utilisez l'un des 2 cteurs mis en cache par le framework (OP utilise le premier). À partir de MSDN: pour augmenter les performances, l'infrastructure de sérialisation XML génère dynamiquement des assemblys pour sérialiser et désérialiser les types spécifiés. Le framework recherche et réutilise ces assemblys. Ce problème se produit uniquement lorsque vous utilisez les ctors suivants: XmlSerializer.XmlSerializer (Type) XmlSerializer.XmlSerializer (Type, String) Référence: msdn.microsoft.com/en-us/library/…
Dave Black
@DaveBlack: Oui, mais ces constructeurs lèvent et interceptent une exception en interne même lorsque l'utilisation est complètement valide. C'est mauvais, et c'est la raison pour laquelle le PO a posé la question en premier lieu.
d - b
@db Vrai, mais ce que je voulais dire (mais ce n'était pas clair - mes excuses) était que les seules lignes de votre soln qui sont nécessaires sont les 3 premières lignes dans la condition else.
Dave Black
8

Pour éviter l'exception, vous devez faire deux choses:

  1. Ajoutez un attribut à la classe sérialisée (j'espère que vous y avez accès)
  2. Générez le fichier de sérialisation avec sgen.exe

Ajoutez l'attribut System.Xml.Serialization.XmlSerializerAssembly à votre classe. Remplacez «MyAssembly» par le nom de l'assembly dans lequel se trouve MyClass.

[Serializable]
[XmlSerializerAssembly("MyAssembly.XmlSerializers")]
public class MyClass
{

}

Générez le fichier de sérialisation à l'aide de l'utilitaire sgen.exe et déployez-le avec l'assembly de la classe.

'sgen.exe MyAssembly.dll' générera le fichier MyAssembly.XmlSerializers.dll

Ces deux modifications feront que le .net trouvera directement l'assembly. Je l'ai vérifié et cela fonctionne sur .NET Framework 3.5 avec Visual Studio 2008

Ami Bar
la source
Ok, et a-t-il échoué sans ces changements, et si oui, pourquoi?
John Saunders
1
Je ne trouve aucune raison pour laquelle mon projet, 4.0 dans VS2012, a soudainement commencé à échouer. "Ignorer" l'erreur n'était pas une option, car elle se produisait chaque fois que j'essayais d'accéder à Active Directory; ainsi ignorer signifierait ne pas s'authentifier. Je suis toujours très frustré que VS2012 ne génère pas automatiquement la DLL de sérialisation correctement. Cependant, ces étapes ont fourni la solution parfaite.
sfuqua
6

Cette exception peut également être interceptée par un assistant de débogage géré (MDA) appelé BindingFailure.

Ce MDA est utile si votre application est conçue pour être livrée avec des assemblys de sérialisation pré-génération. Nous faisons cela pour augmenter les performances de notre application. Cela nous permet de nous assurer que les assemblys de sérialisation pré-construits sont correctement construits par notre processus de construction et chargés par l'application sans être reconstruits à la volée.

Ce n'est vraiment pas utile sauf dans ce scénario, car comme d'autres affiches l'ont dit, lorsqu'une erreur de liaison est interceptée par le constructeur Serializer, l'assembly de sérialisation est reconstruit au moment de l'exécution. Vous pouvez donc généralement le désactiver.

HiredMind
la source
6

La fonction XmlSerializer.FromTypes ne lève pas l'exception, mais elle fuit la mémoire. C'est pourquoi vous devez mettre en cache un tel sérialiseur pour chaque type afin d'éviter une fuite de mémoire pour chaque instance créée.

Créez votre propre fabrique XmlSerializer et utilisez-la simplement:

XmlSerializer serializer = XmlSerializerFactoryNoThrow.Create(typeof(MyType));

L'usine ressemble à:

public static class XmlSerializerFactoryNoThrow
{
    public static Dictionary<Type, XmlSerializer> _cache = new Dictionary<Type, XmlSerializer>();

    private static object SyncRootCache = new object();        

    /// <summary>
    /// //the constructor XmlSerializer.FromTypes does not throw exception, but it is said that it causes memory leaks
    /// http://stackoverflow.com/questions/1127431/xmlserializer-giving-filenotfoundexception-at-constructor
    /// That is why I use dictionary to cache the serializers my self.
    /// </summary>
    public static XmlSerializer Create(Type type)
    {
        XmlSerializer serializer;

        lock (SyncRootCache)
        {
            if (_cache.TryGetValue(type, out serializer))
                return serializer;
        }

        lock (type) //multiple variable of type of one type is same instance
        {
            //constructor XmlSerializer.FromTypes does not throw the first chance exception           
            serializer = XmlSerializer.FromTypes(new[] { type })[0];
            //serializer = XmlSerializerFactoryNoThrow.Create(type);
        }

        lock (SyncRootCache)
        {
            _cache[type] = serializer;
        }
        return serializer;
    }       
}

Version plus compliquée sans possibilité de fuite de mémoire (veuillez consulter le code):

    public static XmlSerializer Create(Type type)
    {
        XmlSerializer serializer;

        lock (SyncRootCache)
        {
            if (_cache.TryGetValue(type, out serializer))
                return serializer;
        }

        lock (type) //multiple variable of type of one type is same instance
        {
            lock (SyncRootCache)
            {
                if (_cache.TryGetValue(type, out serializer))
                    return serializer;
            }
            serializer = XmlSerializer.FromTypes(new[] { type })[0];
            lock (SyncRootCache)
            {
                _cache[type] = serializer;
            }
        }          
        return serializer;
    }       
}
Tomas Kubes
la source
Vous devez utiliser ConcurrentDictionary à la place. Ce code peut bloquer.
Behrooz
Comment peut-il interbloquer si toute la gestion avec le dictionnaire est dans la section de verrouillage?
Tomas Kubes
Désolé, j'ai confondu les mots. Ce que je voulais dire, c'est qu'il peut insérer un élément plus d'une fois. car il y a un écart entre le moment où il vérifie l'existence et le moment où il s'insère. Le dictionnaire simultané utilise une sorte de verrouillage en deux phases (sac [0] puis sac [hachage]]) et conserve une référence au sac qui doit insérer / contenir l'élément que vous travaillez. C'est plus rapide, plus sûr et plus propre.
Behrooz
Oui et non. Vous avez raison de dire qu'il peut arriver qu'en même temps un sérialiseur du même type soit créé sur deux threads en parallèle puis ajouté au dictionnaire deux fois. Dans ce cas, le deuxième insert remplacera simplement le premier, mais la section de verrouillage garantit la sécurité du filetage et l'inconvénient global est une petite fuite de mémoire. Il s'agit d'optimisation des performances, car vous ne voulez pas que le thread un avec le sérialiseur de type A soit bloqué par le thread deux avec le sérialiseur de type B dans le scénario réel.
Tomas Kubes
Je peux imaginer que la solution pourrait être encore meilleure (sans fuite de mémoire théorique), mais plus compliquée.
Tomas Kubes
3

Le dépannage des erreurs de compilation est en revanche très compliqué. Ces problèmes se manifestent dans une FileNotFoundException avec le message:

File or assembly name abcdef.dll, or one of its dependencies, was not found. File name: "abcdef.dll"
   at System.Reflection.Assembly.nLoad( ... )
   at System.Reflection.Assembly.InternalLoad( ... )
   at System.Reflection.Assembly.Load(...)
   at System.CodeDom.Compiler.CompilerResults.get_CompiledAssembly() 

Vous vous demandez peut-être ce qu'une exception de fichier introuvable a à voir avec l'instanciation d'un objet sérialiseur, mais n'oubliez pas: le constructeur écrit des fichiers C # et essaie de les compiler. La pile d'appels de cette exception fournit de bonnes informations pour étayer cette suspicion. L'exception s'est produite alors que XmlSerializer a tenté de charger un assembly généré par CodeDOM appelant la méthode System.Reflection.Assembly.Load. L'exception ne fournit pas d'explication sur la raison pour laquelle l'assembly que le XmlSerializer était censé créer n'était pas présent. En général, l'assembly n'est pas présent car la compilation a échoué, ce qui peut se produire car, dans de rares circonstances, les attributs de sérialisation produisent du code que le compilateur C # ne parvient pas à compiler.

Remarque Cette erreur se produit également lorsque le XmlSerializer s'exécute sous un compte ou un environnement de sécurité qui n'est pas en mesure d'accéder au répertoire temporaire.

Source : http://msdn.microsoft.com/en-us/library/aa302290.aspx

Zyphrax
la source
il n'a pas précisé que cela se produisait au moment de l'exécution. Une autre chose à laquelle je peux penser est que vous avez peut-être un conflit espace de noms / classe. Quel est le nom complet de votre MyType?
Zyphrax
Oui, j'ai vérifié votre lien, les informations sur les constructeurs, bien qu'utiles, n'étaient pas ce dont j'avais besoin.
Irwin
5
@SpaceghostAl Vous pouvez compiler au moment de l'exécution. Et c'est ce que fait XmlSerializer. Il construit dynamiquement au moment de l'exécution un assembly qui (dé) sérialise XML pour le type particulier. Pour une raison quelconque, ce processus échoue pour l'OP. Probablement en raison de problèmes d'autorisation, par exemple sur un répertoire temporaire. (Cela pourrait même être aussi stupide que l'espace disque insuffisant.)
nos
Es-tu sûr de ça? J'étais à peu près sûr que les éléments de sérialisation étaient compilés dans un assembly avec un nom YourAssemblyName.XmlSerializers.dll pendant la génération , non compilés au moment de l'exécution. Cela peut échouer pour toutes sortes de raisons, en particulier toutes les autorisations NTFS dans le dossier de déploiement.
tomfanning le
1
J'aurais aimé pouvoir voter plusieurs fois. Votre note sur le compte ne pouvant pas accéder au dossier temporaire a déclenché la réponse pour moi. Une fois que j'ai ajouté mon compte de service au groupe d'administration sur le serveur, cela a juste fonctionné. Je vous remercie!
Bob Horn
2

Dans les propriétés du projet Visual Studio, il existe une option indiquant «générer un assembly de sérialisation». Essayez de l'activer pour un projet qui génère [Assemblage contenant de MyType].

Pascal
la source
1

Une classe personnalisée à sérialiser:

[Serializable]
public class TestClass
{
    int x = 2;
    int y = 4;
    public TestClass(){}
    public TestClass(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public int TestFunction()
    {
        return x + y;
    }
}

J'ai joint l'extrait de code. Peut-être que cela peut vous aider.

static void Main(string[] args)
{
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(TestClass));

    MemoryStream memoryStream = new MemoryStream();
    XmlTextWriter xmlWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);

    TestClass domain = new TestClass(10, 3);
    xmlSerializer.Serialize(xmlWriter, domain);
    memoryStream = (MemoryStream)xmlWriter.BaseStream;
    string xmlSerializedString = ConvertByteArray2Str(memoryStream.ToArray());

    TestClass xmlDomain = (TestClass)DeserializeObject(xmlSerializedString);

    Console.WriteLine(xmlDomain.TestFunction().ToString());
    Console.ReadLine();
}
shahjapan
la source
2
-1 pour ne pas utiliser de blocs pour éviter les fuites de ressources et pour utiliser XmlTextWriter.
John Saunders
ok d'accord, mais j'ai quand même utilisé XmlSerializer xmlSerializer = new XmlSerializer (typeof (TestClass)); mais je ne reçois pas ladite exception.
shahjapan
1

J'avais un problème similaire et ignorer l'exception ne fonctionnait pas pour moi. Mon code appelait la configuration de NServiceBusConfigure.With(...).XmlSerializer()...

Ce qui m'a permis de changer la plateforme de mon projet.

  1. Allez dans Build \ Configuration Manager ...
  2. Trouvez votre projet et changez de plateforme (dans mon cas de x86 à Any CPU)
kkelley
la source
1

Juste comme référence. Prenant de la réponse et des commentaires de DB, je suis venu avec cette solution qui est proche de la solution DB. Cela fonctionne bien dans tous mes cas et il est sûr pour les threads. Je ne pense pas que l'utilisation d'un ConcurrentDictionary aurait été acceptable.

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace HQ.Util.General
{
    public class XmlSerializerHelper
    {
        private static readonly Dictionary<Type, XmlSerializer> _dictTypeToSerializer = new Dictionary<Type, XmlSerializer>();

        public static XmlSerializer GetSerializer(Type type)
        {
            lock (_dictTypeToSerializer)
            {
                XmlSerializer serializer;
                if (! _dictTypeToSerializer.TryGetValue(type, out serializer))
                {
                    var importer = new XmlReflectionImporter();
                    var mapping = importer.ImportTypeMapping(type, null, null);
                    serializer = new XmlSerializer(mapping);
                    return _dictTypeToSerializer[type] = serializer;
                }

                return serializer;
            }
        }
    }
}

Usage:

        if (File.Exists(Path))
        {
            using (XmlTextReader reader = new XmlTextReader(Path))
            {
                // XmlSerializer x  = new XmlSerializer(typeof(T));
                var x = XmlSerializerHelper.GetSerializer(typeof(T));

                try
                {
                    options = (OptionsBase<T>)x.Deserialize(reader);
                }
                catch (Exception ex)
                {
                    Log.Instance.AddEntry(LogType.LogException, "Unable to open Options file: " + Path, ex);
                }
            }
        }
Eric Ouellet
la source
0

Votre type peut référencer d'autres assemblys qui ne peuvent être trouvés ni dans le GAC ni dans votre dossier bin local ==> ...

"ou l'une de ses dépendances. Le système ne trouve pas le fichier spécifié"

Pouvez-vous donner un exemple du type que vous souhaitez sérialiser?

Remarque: assurez-vous que votre type implémente Sérialisable.

Henrik
la source
0

J'obtenais la même erreur, et c'était dû au type que j'essayais de désérialiser de ne pas avoir de constructeur sans paramètre par défaut . J'ai ajouté un constructeur et il a commencé à fonctionner.

kay.one
la source
0

J'ai eu le même problème jusqu'à ce que j'utilise un outil tiers pour générer la classe à partir du XSD et cela a fonctionné! J'ai découvert que l'outil ajoutait du code supplémentaire en haut de ma classe. Lorsque j'ai ajouté ce même code en haut de ma classe d'origine, cela a fonctionné. Voici ce que j'ai ajouté ...

#pragma warning disable
namespace MyNamespace
{
  using System;
  using System.Diagnostics;
  using System.Xml.Serialization;
  using System.Collections;
  using System.Xml.Schema;
  using System.ComponentModel;
  using System.Xml;
  using System.Collections.Generic;

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1064.2")]
  [System.SerializableAttribute()]
  [System.Diagnostics.DebuggerStepThroughAttribute()]
  [System.ComponentModel.DesignerCategoryAttribute("code")]
  [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
  [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
  public partial class MyClassName
  {
  ...
TheJonz
la source
0

Vu beaucoup de recommandations à utiliser ConcurrentDictionary, mais pas d'exemples solides, donc je vais jeter mon chapeau dans cette course aux solutions. Je ne suis pas un développeur thread-safe, donc si ce code n'est pas solide, veuillez parler pour ceux qui suivront.

public static class XmlSerializerHelper
{
    private static readonly ConcurrentDictionary<Type, XmlSerializer> TypeSerializers = new ConcurrentDictionary<Type, XmlSerializer>();

    public static XmlSerializer GetSerializer(Type type)
    {
        return TypeSerializers.GetOrAdd(type,
        t =>
        {
            var importer = new XmlReflectionImporter();
            var mapping = importer.ImportTypeMapping(t, null, null);
            return new XmlSerializer(mapping);
        });
    }
}

J'ai vu d'autres articles impliquer ConcurrentDictionaryet Lazycharger la valeur. Je ne sais pas si c'est pertinent ici ou non, mais voici le code pour cela:

private static readonly ConcurrentDictionary<Type, Lazy<XmlSerializer>> TypeSerializers = new ConcurrentDictionary<Type, Lazy<XmlSerializer>>();

public static XmlSerializer GetSerializer(Type type)
{
    return TypeSerializers.GetOrAdd(type,
    t =>
    {
        var importer = new XmlReflectionImporter();
        var mapping = importer.ImportTypeMapping(t, null, null);
        var lazyResult = new Lazy<XmlSerializer>(() => new XmlSerializer(mapping), LazyThreadSafetyMode.ExecutionAndPublication);
        return lazyResult;
    }).Value;
}
Airn5475
la source