XmlSerializer fornisce FileNotFoundException al costruttore


347

Un'applicazione con cui sto lavorando non riesce quando provo a serializzare i tipi.

Un'affermazione come

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

produce:

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)

Non definisco alcun serializzatore speciale per la mia classe.

Come posso risolvere questo problema?


5
OK, quindi questa domanda è solo la mia versione C # di una domanda VB già posta: stackoverflow.com/questions/294659/… Grazie ragazzi.
Irwin,

1
Sei anni dopo, la risposta di @VladV è la soluzione più semplice e meno dannosa. Basta cambiare il Generate serialization assemblymenu a discesa su "Attivo", anziché su "Auto".
Heliac,

@Heliac: non sono d'accordo. Non sempre funziona. Si prega di vedere il commento di Benoit Blanchon alla risposta di Vlad. La risposta più semplice per me è non usare String.Collection nei file di configurazione. Invece uso: string [] items = Settings.Default.StringofNewlineDelimitedItems.Split (new [] {Environment.NewLine});
Andrew Dennison,

Risposte:


388

Che ci crediate o no, questo è un comportamento normale. Viene generata un'eccezione ma gestita da XmlSerializer, quindi se la ignori, tutto dovrebbe continuare bene.

L'ho trovato molto fastidioso e ci sono state molte lamentele a riguardo se cerchi un po 'in giro, ma da quello che ho letto Microsoft non ha intenzione di fare nulla al riguardo.

Durante il debug è possibile evitare di visualizzare sempre popup di eccezione se si disattivano le eccezioni della prima possibilità per quella specifica eccezione. In Visual Studio, vai su Debug -> Exceptions (o premi Ctrl+ Alt+ E), Common Language Runtime Exceptions -> System.IO -> System.IO.FileNotFoundException .

Puoi trovare informazioni su un altro modo per aggirarlo nel post del blog Eccezione FileNotFound C # XmlSerializer (che discute lo strumento XmlSerializerPreCompiler di Chris Sells ).


162
Uno dei modi possibili per eliminare questo problema è selezionare l'opzione "Solo il mio codice" in Strumenti -> Opzioni -> Debug -> Opzioni generali.
Frederic,

26
@Frederic: questo commento è fantastico! Sono seduto qui con un "WTF !?" espressione sulla mia faccia, cercando di cacciare questa eccezione spuria e trovo questa domanda, con risposta (è colpa di Microsoft, cos'altro c'è di nuovo?), ma non volevo disabilitare la gestione delle eccezioni, perché potrei averne bisogno per il mio codice. A +!
Kumba,

27
Penso che il suggerimento di Hans di seguito sia più prezioso: usa una diversa chiamata di metodo che non produce affatto questa eccezione: XmlSerializer serializer = XmlSerializer.FromTypes (new [] {typeof (MyType)}) [0];
luminoso

3
Il problema è che questo fallisce il mio test, quindi non posso semplicemente "ignorare" l'eccezione
Csaba Toth,

16
Mi dispiace, ma questo è un suggerimento terribile. FileNotFoundException è uno dei più comuni, secondo la mia esperienza, e la disabilitazione di questa segnalazione di eccezioni richiede solo problemi in futuro. Meglio attivare "Just My Code" o abilitare la creazione di assembly di serializzazione descritti di seguito.
Quarkly,

104

Come ha detto Martin Sherburn, questo è un comportamento normale. Il costruttore di XmlSerializer tenta innanzitutto di trovare un assembly denominato [YourAssembly] .XmlSerializers.dll che dovrebbe contenere la classe generata per la serializzazione del tipo. Poiché tale DLL non è stata ancora generata (non lo sono per impostazione predefinita), viene generata una FileNotFoundException. Quando ciò accade, il costruttore di XmlSerializer rileva quell'eccezione e la DLL viene generata automaticamente in fase di esecuzione dal costruttore di XmlSerializer (ciò viene generato generando i file di origine C # nella directory% temp% del computer, quindi compilarli utilizzando il compilatore C #). Le costruzioni aggiuntive di un XmlSerializer per lo stesso tipo utilizzeranno solo la DLL già generata.

AGGIORNAMENTO: a partire da .NET 4.5, XmlSerializernon esegue più la generazione di codice né esegue la compilazione con il compilatore C # per creare un assembly serializzatore in fase di esecuzione, a meno che non sia esplicitamente forzato impostando un'impostazione del file di configurazione ( useLegacySerializerGeneration ). Questa modifica rimuove la dipendenza csc.exee migliora le prestazioni di avvio. Fonte: file Leggimi di .NET Framework 4.5 , sezione 1.3.8.1.

L'eccezione è gestita dal costruttore di XmlSerializer. Non è necessario fare nulla da soli, è sufficiente fare clic su "Continua" (F5) per continuare l'esecuzione del programma e tutto andrà bene. Se sei infastidito dalle eccezioni che interrompono l'esecuzione del tuo programma e spuntano un helper di eccezione, o hai "Just My Code" disattivato o hai FileNotFoundException impostato per interrompere l'esecuzione quando viene lanciato, anziché quando "Utente- non gestita'.

Per abilitare "Solo il mio codice", vai su Strumenti >> Opzioni >> Debug >> Generale >> Abilita solo il mio codice. Per disattivare l'interruzione dell'esecuzione quando viene generato FileNotFound, vai su Debug >> Eccezioni >> Trova >> inserisci 'FileNotFoundException' >> deseleziona la casella di controllo 'Gettato' da System.IO.FileNotFoundException.


+1 per l'aggiornamento: questo spiega il diverso comportamento durante il debug dei casi di test
mbx

3
Il tuo aggiornamento suggerisce che questa eccezione non dovrebbe verificarsi in .NET 4.5, ma la sto ancora vedendo.
Timbo,

@ Timbo: non vedo perché non si ottiene tale eccezione con .NET 4.5. Cerca ancora un file e, se il file è mancante, FileNotFoundExceptionverrà lanciato un. La differenza non è nel modo in cui viene verificata l'esistenza dell'assembly, ma nel modo in cui generarlo una volta determinato che manca. Prima, utilizzava la generazione testuale di codice C # con una chiamata al compilatore C # per creare IL. A partire da .NET 4.5 emette IL direttamente, senza l'uso di un compilatore.
Allon Guralnek,

1
Vorrei solo che MS lo implementasse come se (File.Exists (...)) {Load} else {Fallback} invece di provare {Load} catch {Fallback}. Il controllo del flusso basato sull'eccezione ha un cattivo odore e rende la mia esperienza di debug più difficile e fragile del necessario.
Timbo,

1
@ Timbo: un semplice File.Exists()potrebbe non essere sufficiente. Individuare un assembly non è un affare semplice, il runtime appare in diverse posizioni e credo che il comportamento cambi in base all'ambiente (applicazione console vs essere ospitato in IIS, ecc.). Immagino che ciò che avrebbe dovuto essere implementato era TryLoadAssembly()qualcosa o qualcosa di simile.
Allon Guralnek,

63

Nelle proprietà del progetto Visual Studio (pagina "Build", se ricordo bene) c'è un'opzione che dice "genera assembly di serializzazione". Prova ad attivarlo per un progetto che genera [Contenente Assembly di MyType] .


4
Vedere anche stackoverflow.com/a/8798289/1164966 se l'assembly di serializzazione non è ancora generato da Visual Studio.
Benoit Blanchon,

Risposta migliore, più chiara, concisa! Vorrei poter votare di nuovo anche io!
John Zabroski,

59

C'è una soluzione per questo. Se usi

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

dovrebbe evitare quell'eccezione. Questo ha funzionato per me.

ATTENZIONE: non utilizzare più volte, altrimenti si verificherà una perdita di memoria

Perderai memoria come un matto se usi questo metodo per creare istanze dello XmlSerializerstesso tipo più di una volta!

Questo perché questo metodo ignora la memorizzazione nella cache integrata fornita dai costruttori XmlSerializer(type)e XmlSerializer(type, defaultNameSpace)(anche tutti gli altri costruttori ignorano la cache).

Se si utilizza un metodo per creare un XmlSerializer che non è tramite questi due costruttori, è necessario implementare la propria cache o emorragia memoria.


44
ATTENZIONE: perderai memoria come un matto se usi questo metodo per creare istanze XmlSerializerper lo stesso tipo più di una volta! Questo perché questo metodo ignora la memorizzazione nella cache integrata fornita dai costruttori XmlSerializer(type)e XmlSerializer(type, defaultNameSpace)(anche tutti gli altri costruttori ignorano la cache). Se si utilizza un metodo per creare un metodo XmlSerializerdiverso da questi due costruttori, è necessario implementare la propria memorizzazione nella cache o emorragia memoria.
Allon Guralnek,

4
@AllonGuralnek Beh, sarò dannato ... hai assolutamente ragione; scavare ulteriormente tramite Reflector mostra che mentre controlla la cache, lo fa dopo aver generato il gruppo di serializzazione! Wtf?!?
JerKimball


3
@JerKimball: quella pagina non sta mentendo. Come hai scoperto, FromTypessembra popolare la cache. Quindi dovrebbe essere un modo valido per riscaldare una XmlSerializercache vuota in un'istruzione (come suggerisce l'articolo), ma un modo davvero brutto per recuperare qualcosa da essa (dovrebbe essere fatto solo tramite i costruttori più semplici). In ogni caso, non sapevo che si trattava di un bug, ho sempre pensato che qualsiasi cosa che perdesse dovrebbe perdere (come i XmlSerializercostruttori più avanzati ). Non avrei nemmeno preso in considerazione l'uso FromTypes()poiché puoi semplicemente farlo types.Select(t => new XmlSerializer(t)).
Allon Guralnek, il

2
@AllonGuralnek L'aspetto non esplorativo dell'uso FromTypesha il suo fascino - anche se le eccezioni lanciate sono tutte colte, è un'operazione preziosa; l'approccio "cache your your way" sembra essere l'unica soluzione, poiché l'unica correzione ufficialmente supportata sembra trovarsi in un oscuro assembly basato sul Web. (modifica: francamente, sono tutto per il porting di tutto sui contratti di dati :))
JerKimball

22

Ho riscontrato questo problema esatto e non sono riuscito a risolverlo con nessuna delle soluzioni menzionate.

Poi ho finalmente trovato una soluzione. Sembra che il serializzatore abbia bisogno non solo del tipo, ma anche dei tipi nidificati. Cambiando questo:

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

A questo:

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

Risolto il problema per me. Niente più eccezioni o altro.


8
Questo ha funzionato per me. Utilizzando .Net4.0 il formato èvar xmlSerializer = new XmlSerializer(typeof(T), typeof(T).GetNestedTypes());
user3161729

1
Questo ha funzionato anche per me. Ma sembra essere necessario solo durante la serializzazione, non durante la deserializzazione. Forse ha senso, forse no.
SteveCinq,

2
Questo produce anche perdita di memoria, se eseguito molte volte.
Volodymyr Kotylo,

9

La mia soluzione è andare direttamente alla riflessione per creare il serializzatore. Questo ignora il caricamento strano file che causa l'eccezione. L'ho impacchettato in una funzione di supporto che si occupa anche della memorizzazione nella cache del serializzatore.

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;
    }
}

2 problemi qui: in primo luogo il codice non è thread-safe e in secondo luogo (cosa ancora più importante) si sta tentando di replicare ciò che il runtime .net fa già (in base al ctor che si sta utilizzando). cioè non è necessario questo codice
Dave Black,

@DaveBlack: Sì, la risposta di quadfinity con la memorizzazione nella cache di un ConcurrentDictionary sarebbe migliore
d - b

@db Il mio secondo punto era che la memorizzazione nella cache non è nemmeno necessaria - purché si stia utilizzando uno dei 2 segnalatori che il framework memorizza nella cache (OP utilizza il primo). Da MSDN: per aumentare le prestazioni, l'infrastruttura di serializzazione XML genera dinamicamente assembly per serializzare e deserializzare i tipi specificati. Il framework trova e riutilizza tali assemblee. Questo comportamento si verifica solo quando si utilizzano i seguenti ctors: XmlSerializer.XmlSerializer (Type) XmlSerializer.XmlSerializer (Type, String) Riferimento: msdn.microsoft.com/en-us/library/…
Dave Black

@DaveBlack: Sì, ma questi costruttori generano e rilevano un'eccezione internamente anche quando l'utilizzo è completamente valido. Ciò è negativo e questo è il motivo per cui l'OP ha posto la domanda in primo luogo.
d - b

@db Vero, ma quello che volevo dire (ma non era chiaro - le mie scuse) era che le uniche righe del tuo soln che sono necessarie sono le prime 3 righe nella condizione else.
Dave Black,

8

Per evitare l'eccezione, devi fare due cose:

  1. Aggiungi un attributo alla classe serializzata (spero che tu abbia accesso)
  2. Generare il file di serializzazione con sgen.exe

Aggiungi l'attributo System.Xml.Serialization.XmlSerializerAssembly alla tua classe. Sostituisci "MyAssembly" con il nome dell'assembly in cui si trova MyClass.

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

}

Generare il file di serializzazione utilizzando l'utilità sgen.exe e distribuirlo con l'assembly della classe.

'sgen.exe MyAssembly.dll' genererà il file MyAssembly.XmlSerializers.dll

Queste due modifiche indurranno il .net a trovare direttamente l'assembly. L'ho verificato e funziona su .NET Framework 3.5 con Visual Studio 2008


Ok, e ha fallito senza questi cambiamenti, e se sì, perché?
John Saunders,

1
Non riesco a trovare alcun motivo per cui il mio progetto, 4.0 in VS2012, abbia improvvisamente iniziato a fallire. "Ignorare" l'errore non era un'opzione, perché si verificava ogni volta che tentavo di accedere ad Active Directory; quindi ignorare significherebbe non autenticarsi. Sono ancora molto frustrato dal fatto che VS2012 non generi automaticamente la DLL di serializzazione correttamente. Tuttavia, questi passaggi hanno fornito la soluzione perfetta.
sfuqua,

6

Questa eccezione può anche essere intrappolata da un assistente di debug gestito (MDA) chiamato BindingFailure.

Questo MDA è utile se l'applicazione è progettata per essere fornita con assiemi di serializzazione pre-build. Facciamo questo per aumentare le prestazioni per la nostra applicazione. Ci consente di assicurarci che gli assiemi di serializzazione precompilati vengano correttamente creati dal nostro processo di compilazione e caricati dall'applicazione senza essere ricostruiti al volo.

Non è davvero utile, tranne in questo scenario, perché, come hanno detto altri poster, quando un errore di associazione viene intrappolato dal costruttore del serializzatore, l'assieme di serializzazione viene ricostruito in fase di esecuzione. Quindi di solito puoi spegnerlo.


6

La funzione XmlSerializer.FromTypes non genera l'eccezione, ma perde la memoria. Ecco perché è necessario memorizzare nella cache tale serializzatore per ogni tipo per evitare perdite di memoria per ogni istanza creata.

Crea la tua fabbrica XmlSerializer e usala semplicemente:

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

La fabbrica sembra simile a:

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;
    }       
}

Versione più complicata senza possibilità di perdita di memoria (per favore qualcuno riveda il codice):

    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;
    }       
}

Si dovrebbe usare ConcurrentDictionary invece. Questo codice può deadlock.
Behrooz,

Come può deadlock se tutta la gestione con dizionario è nella sezione di blocco?
Tomas Kubes,

Scusa, ho confuso le parole. Quello che volevo dire è che può inserire un elemento più di una volta. perché c'è un divario tra quando verifica l'esistenza e quando si inserisce. dizionario simultaneo utilizza una sorta di chiusura a due fasi (bag [0] e quindi bag [hash]]) e mantiene un riferimento al bag che deve inserire / contenere l'oggetto su cui stai lavorando. È più veloce, più sicuro e più pulito.
Behrooz,

Sì e no. Hai ragione che può succedere che nello stesso tempo un serializzatore dello stesso tipo verrà creato su due thread in parallelo e poi aggiunto al dizionario due volte. In tal caso, il secondo inserto sostituirà solo il primo, ma la sezione di blocco garantisce la sicurezza del thread e lo svantaggio generale è una piccola perdita di memoria. Questa è l'ottimizzazione delle prestazioni, perché non vuoi che il thread uno con Serializer di tipo A attenda di essere bloccato dal thread due con serializzatore di tipo B nello scenario reale.
Tomas Kubes,

Posso immaginare che la soluzione potrebbe essere ancora migliore (senza perdita teorica di memoria), ma più complicata.
Tomas Kubes,

3

La risoluzione dei problemi relativi agli errori di compilazione è invece molto complicata. Questi problemi si manifestano in FileNotFoundException con il messaggio:

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() 

Potresti chiederti cosa ha a che fare un file non trovato con l'istanza di un oggetto serializzatore, ma ricorda: il costruttore scrive i file C # e prova a compilarli. Lo stack di chiamate di questa eccezione fornisce alcune buone informazioni a supporto di tale sospetto. L'eccezione si è verificata mentre XmlSerializer ha tentato di caricare un assembly generato da CodeDOM chiamando il metodo System.Reflection.Assembly.Load. L'eccezione non fornisce una spiegazione del perché l'assembly che XmlSerializer avrebbe dovuto creare non fosse presente. In generale, l'assembly non è presente perché la compilazione non è riuscita, il che può accadere perché, in rare circostanze, gli attributi di serializzazione producono codice che il compilatore C # non riesce a compilare.

Nota Questo errore si verifica anche quando XmlSerializer viene eseguito con un account o un ambiente di sicurezza che non è in grado di accedere alla directory temporanea.

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


non ha specificato che questo accadesse in fase di esecuzione. Un'altra cosa a cui riesco a pensare è che forse hai un conflitto tra spazio dei nomi / classe. Qual è il nome completo del tuo MyType?
Zyphrax,

Sì, ho controllato il tuo link, le informazioni sui costruttori, sebbene utili, non erano ciò di cui avevo bisogno.
Irwin,

5
@SpaceghostAl È possibile compilare in fase di esecuzione. Ed è quello che fa XmlSerializer. Costruisce in modo dinamico in fase di esecuzione un assembly che (de) serializza XML per il tipo specifico. Per qualsiasi motivo, questo processo fallisce per l'OP. Probabilmente a causa di problemi di autorizzazione, ad esempio su una directory temporanea. (Potrebbe essere tanto stupido quanto anche sullo spazio su disco.)
nn

Sei sicuro di questo? Ero abbastanza sicuro che le cose di serializzazione venivano compilate in un assembly con un nome YourAssemblyName.XmlSerializers.dll durante la compilazione , non compilato in fase di esecuzione. Ciò potrebbe non riuscire per una serie di motivi, almeno per tutte le autorizzazioni NTFS nella cartella di distribuzione.
tomfanning

1
Vorrei poter votare più volte. La tua nota sull'account che non è stato in grado di accedere alla cartella temp ha innescato la risposta per me. Una volta aggiunto il mio account di servizio al gruppo admin sul server, ha funzionato. Grazie!
Bob Horn,

2

Nelle proprietà del progetto Visual Studio esiste un'opzione che dice "genera assembly di serializzazione". Prova ad attivarlo per un progetto che genera [Contenente Assembly di MyType].


1

Una classe personalizzata per serializzare:

[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;
    }
}

Ho allegato lo snippet di codice. Forse questo può aiutarti.

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();
}

2
-1 per non usare blocchi per prevenire perdite di risorse e per usare XmlTextWriter.
John Saunders,

ok d'accordo, ma ho ancora usato XmlSerializer xmlSerializer = new XmlSerializer (typeof (TestClass)); ma non ottengo la suddetta eccezione.
Shahjapan,

1

Stavo avendo un problema simile e ignorare l'eccezione non ha funzionato per me. Il mio codice stava chiamando la configurazione di NServiceBusConfigure.With(...).XmlSerializer()...

Ciò che mi ha risolto è stato cambiare la piattaforma per il mio progetto.

  1. Vai a Build \ Configuration Manager ...
  2. Trova il tuo progetto e cambia piattaforma (nel mio caso da x86 a qualsiasi CPU)

1

Proprio come riferimento. Prendendo dalla risposta e dai commenti del DB, sono arrivato con questa soluzione che si avvicina alla soluzione DB. Funziona bene in tutti i miei casi ed è thread-safe. Non penso che usare un ConcurrentDictionary sarebbe stato ok.

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;
            }
        }
    }
}

Uso:

        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);
                }
            }
        }

0

Il tuo tipo può fare riferimento ad altri assembly che non possono essere trovati né nel GAC né nella cartella bin locale ==> ...

"o una delle sue dipendenze. Il sistema non riesce a trovare il file specificato"

Puoi fare un esempio del tipo che vuoi serializzare?

Nota: assicurarsi che il tipo implementa Serializable.


0

Stavo ottenendo lo stesso errore ed era dovuto al tipo che stavo cercando di deserializzare non avendo un costruttore senza parametri predefinito . Ho aggiunto un costruttore e ha iniziato a funzionare.


0

Ho avuto lo stesso problema fino a quando non ho usato uno strumento di terze parti per generare la classe dall'XSD e ha funzionato! Ho scoperto che lo strumento stava aggiungendo del codice aggiuntivo nella parte superiore della mia classe. Quando ho aggiunto questo stesso codice all'inizio della mia classe originale ha funzionato. Ecco cosa ho aggiunto ...

#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
  {
  ...

0

ConcurrentDictionaryHo visto molti consigli per usarne uno , ma non ci sono esempi concreti, quindi lancerò il mio cappello in questa gara di soluzioni. Non sono uno sviluppatore thread-safe, quindi se questo codice non è solido, per favore parla per il bene di coloro che seguono.

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);
        });
    }
}

Ho visto altri post che coinvolgono ConcurrentDictionarye Lazycaricano il valore. Non sono sicuro che sia rilevante qui o no, ma ecco il codice per questo:

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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.