XmlSerializer dando FileNotFoundException no construtor

347

Um aplicativo com o qual estou trabalhando está falhando quando tento serializar tipos.

Uma declaração como

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

produz:

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)

Não defino nenhum serializador especial para minha classe.

Como posso resolver este problema?

Irwin
fonte
5
OK, essa pergunta é apenas minha versão em C # de uma pergunta VB já feita: stackoverflow.com/questions/294659/… Obrigado pessoal.
Irwin
11
Seis anos depois, a resposta da @VladV é a solução mais simples e menos adversa. Basta alterar o Generate serialization assemblymenu suspenso para "Ativado", em vez de "Automático".
Heliac
@Heliac: eu discordo. Nem sempre funciona. Por favor, veja o comentário de Benoit Blanchon na resposta de Vlad. A resposta mais simples para mim é não usar String.Collection nos arquivos de configuração. Em vez disso, uso: string [] items = Settings.Default.StringofNewlineDelimitedItems.Split (new [] {Environment.NewLine});
Andrew Dennison

Respostas:

388

Acredite ou não, este é um comportamento normal. Uma exceção é lançada, mas tratada pelo XmlSerializer, portanto, se você a ignorar, tudo deve continuar bem.

Achei isso muito irritante e houve muitas queixas sobre isso, se você pesquisar um pouco, mas pelo que li, a Microsoft não planeja fazer nada a respeito.

Você pode evitar a obtenção de pop-ups de exceção o tempo todo durante a depuração se desativar as exceções de primeira chance para essa exceção específica. No Visual Studio, vá para Debug -> Exceptions (ou pressione Ctrl+ Alt+ E), Common Language Runtime Exceptions -> System.IO -> System.IO.FileNotFoundException .

Você pode encontrar informações sobre outra maneira de contornar isso na postagem do blog C # XmlSerializer FileNotFound (que discute a ferramenta XmlSerializerPreCompiler da ferramenta de Chris Sells ).

Martin Sherburn
fonte
162
Uma das maneiras possíveis de se livrar desse problema é a opção "Apenas meu código" em Ferramentas -> Opções -> Depuração -> Opções gerais.
Frederic
26
@Frederic: Este comentário é incrível! Estou sentado aqui com um "WTF !?" expressão no meu rosto, tentando caçar essa exceção espúria, e eu encontro essa pergunta com resposta (a culpa é da Microsoft, o que mais há de novo?), mas eu não queria desativar o tratamento de exceções, porque talvez eu precise dela para meu código A +!
Kumba
27
Eu acho que a sugestão de Hans abaixo é mais valiosa - use uma chamada de método diferente que não produz essa exceção: XmlSerializer serializer = XmlSerializer.FromTypes (new [] {typeof (MyType)}) [0];
brilhante
3
O problema é que isso não o meu teste, então eu não posso simplesmente "ignorar" a exceção
Csaba Toth
16
Sinto muito, mas esta é uma sugestão terrível. FileNotFoundException é um dos mais comuns, na minha experiência, e desabilitar esse relatório de exceção está apenas pedindo problemas em algum dia no futuro. É melhor ativar 'Just My Code' ou habilitar a criação de assemblies de serialização descritos abaixo.
Quarkly
104

Como Martin Sherburn disse, esse é um comportamento normal. O construtor do XmlSerializer primeiro tenta localizar um assembly chamado [YourAssembly] .XmlSerializers.dll que deve conter a classe gerada para serialização do seu tipo. Como essa DLL ainda não foi gerada (não é por padrão), é lançada uma FileNotFoundException. Quando isso acontece, o construtor do XmlSerializer captura essa exceção e a DLL é gerada automaticamente em tempo de execução pelo construtor do XmlSerializer (isso é feito gerando arquivos de origem C # no diretório% temp% do seu computador e compilando-os usando o compilador C #). Construções adicionais de um XmlSerializer para o mesmo tipo usarão apenas a DLL já gerada.

ATUALIZAÇÃO: A partir do .NET 4.5, XmlSerializernão realiza mais a geração de código nem a compilação com o compilador C # para criar um assembly de serializador em tempo de execução, a menos que seja explicitamente forçado a definir uma configuração de arquivo de configuração ( useLegacySerializerGeneration ). Essa alteração remove a dependência csc.exee melhora o desempenho da inicialização. Fonte: Leiame do .NET Framework 4.5 , seção 1.3.8.1.

A exceção é tratada pelo construtor do XmlSerializer. Não é necessário fazer nada, basta clicar em 'Continuar' (F5) para continuar executando o programa e tudo ficará bem. Se você está incomodado com as exceções que interrompem a execução do programa e exibem um auxiliar de exceção, você tem o 'Just My Code' desativado ou o FileNotFoundException definido para interromper a execução quando lançada, em vez de quando 'User- sem tratamento ".

Para ativar 'Just My Code', vá para Ferramentas >> Opções >> Depuração >> Geral >> Ativar Just My Code. Para desativar a interrupção da execução quando o FileNotFound for acionado, vá para Debug >> Exceptions >> Find >>, digite 'FileNotFoundException' >> desmarque a caixa de seleção 'Thrown' em System.IO.FileNotFoundException.

Allon Guralnek
fonte
+1 para a atualização: isso explica o comportamento diferente ao depurar casos de teste
mbx
3
Sua atualização sugere que essa exceção não deve ocorrer no .NET 4.5, mas ainda estou vendo.
Timbo
@ Timbo: Não vejo por que você não receberia essa exceção com o .NET 4.5. Ele ainda procura um arquivo e, se o arquivo estiver ausente, um FileNotFoundExceptionserá lançado. A diferença não está em como a existência da montagem é verificada, mas em como gerá-la quando é determinado que está faltando. Antes, usava a geração de código C # textual com uma chamada para o compilador C # para criar a IL. A partir do .NET 4.5, emite IL diretamente, sem o uso de um compilador.
Allon Guralnek
11
Eu só gostaria que a MS implementasse isso como se (File.Exists (...)) {Load} else {Fallback} em vez de tentar {Load} catch {Fallback}. O controle de fluxo baseado em exceção tem um cheiro ruim e torna minha experiência de depuração mais difícil e frágil do que o necessário.
Timbo 28/07
11
@ Timbo: Um simples File.Exists()pode não ser suficiente. A localização de um assembly não é uma tarefa simples, o tempo de execução é exibido em vários locais e acredito que o comportamento muda de acordo com o ambiente (aplicativo do console x hospedado no IIS, etc.). Eu acho que o que deveria ter sido implementado foi um TryLoadAssembly()ou algo semelhante.
Allon Guralnek
63

Nas propriedades do projeto do Visual Studio (página "Build", se bem me lembro), existe uma opção dizendo "gerar assembly de serialização". Tente ativá-lo para um projeto que gera [Contendo Assembly do MyType] .

VladV
fonte
4
Consulte também stackoverflow.com/a/8798289/1164966 se o assembly de serialização ainda não for gerado pelo Visual Studio.
Benoit Blanchon
Melhor, mais clara, sucinta resposta! Eu gostaria de poder votar novamente também!
John Zabroski
59

Existe uma solução alternativa para isso. Se você usar

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

deve evitar essa exceção. Isso funcionou para mim.

AVISO: Não use várias vezes, ou você terá um vazamento de memória

Você perderá memória como um louco se usar esse método para criar instâncias do XmlSerializermesmo tipo mais de uma vez!

Isso ocorre porque esse método ignora o cache interno fornecido aos construtores XmlSerializer(type)e XmlSerializer(type, defaultNameSpace)(todos os outros construtores também ignoram o cache).

Se você usar qualquer método para criar um XmlSerializer que não seja desses dois construtores, implemente seu próprio cache ou sofrerá hemorragia na memória.

quadfinity
fonte
44
AVISO: Você vazará memória como uma louca se usar esse método para criar instâncias do XmlSerializermesmo tipo mais de uma vez! Isso ocorre porque esse método ignora o cache interno fornecido aos construtores XmlSerializer(type)e XmlSerializer(type, defaultNameSpace)(todos os outros construtores também ignoram o cache). Se você usar qualquer método para criar um método XmlSerializerque não seja através desses dois construtores, deverá implementar seu próprio cache ou sofrerá hemorragia na memória.
Allon Guralnek
4
@AllonGuralnek Bem, eu vou ser amaldiçoado ... você está absolutamente correto; uma pesquisa mais aprofundada via Reflector mostra que, embora verifique o cache, o faz após gerar o conjunto de serialização! Wtf?!?
precisa saber é o seguinte
4
Acontece que é um bug conhecido: weblogs.asp.net/cschittko/archive/2005/01/14/353435.aspx
JerKimball
3
@JerKimball: Essa página não está mentindo. Como você descobriu, FromTypesparece preencher o cache. Portanto, deve ser uma maneira válida de aquecer um XmlSerializercache vazio em uma instrução (como o artigo sugere), mas uma maneira realmente ruim de recuperar qualquer coisa a partir dele (deve ser feita apenas pelos construtores mais simples). De qualquer forma, eu não sabia que era um bug, sempre pensei que qualquer coisa que vazasse deveria vazar (como os XmlSerializerconstrutores mais avançados ). Eu nem consideraria usar, FromTypes()já que você pode fazer types.Select(t => new XmlSerializer(t)).
Allon Guralnek
2
@AllonGuralnek O aspecto não sondador do uso FromTypestem seu apelo - mesmo que as exceções lançadas sejam todas capturadas, é uma operação inestimável; a abordagem 'cache à sua maneira' parece ser a única solução alternativa, pois a única correção oficialmente suportada parece estar em um assembly obscuro baseado na Web. (edit: francamente, eu sou todo para portar tudo para contratos de dados :))
JerKimball
22

Corri para esse problema exato e não consegui contornar isso com nenhuma das soluções mencionadas.

Então eu finalmente encontrei uma solução. Parece que o serializador precisa não apenas do tipo, mas também dos tipos aninhados. Alterando isso:

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

Para isso:

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

Corrigido o problema para mim. Sem mais exceções ou qualquer coisa.

Gelado
fonte
8
Isso funcionou para mim. Usando .Net4.0 o formato évar xmlSerializer = new XmlSerializer(typeof(T), typeof(T).GetNestedTypes());
user3161729
11
Isso funcionou para mim também. Mas apenas parece ser necessário quando serializado, não quando desserializado. Talvez isso faça sentido, talvez não.
SteveCinq
2
Isso também produz vazamento de memória, se executado muitas vezes.
Volodymyr Kotylo 13/03/19
9

Minha solução é ir direto à reflexão para criar o serializador. Isso ignora o carregamento estranho de arquivo que causa a exceção. Empacotei isso em uma função auxiliar que também cuida do armazenamento em cache do serializador.

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
fonte
2 problemas aqui - primeiro, seu código não é seguro para threads e, segundo (mais importante), você está tentando replicar o que o tempo de execução .net já faz (com base no ctor que você está usando). ou seja, não há necessidade desse código #
Dave Black
@DaveBlack: Sim, a resposta de quadfinity com o cache para um ConcurrentDictionary seria melhor
d - b
@db Meu segundo ponto foi que o cache não é necessário - contanto que você esteja usando um dos 2 ctors que o framework armazena em cache (o OP está usando o primeiro). No MSDN: para aumentar o desempenho, a infraestrutura de serialização XML gera dinamicamente assemblies para serializar e desserializar tipos especificados. A estrutura localiza e reutiliza esses assemblies. Este comportamento ocorre apenas quando utilizar os seguintes ctors: XmlSerializer.XmlSerializer (Type) XmlSerializer.XmlSerializer (Type, String) Referencia: msdn.microsoft.com/en-us/library/...
Dave Preto
@DaveBlack: Sim, mas esses construtores lançam e capturam uma exceção internamente, mesmo quando o uso é completamente válido. Isso é ruim e é por isso que o OP fez a pergunta em primeiro lugar.
d - b
@db É verdade, mas o que eu queria dizer (mas não estava claro - minhas desculpas) era que as únicas linhas do seu soln necessárias são as primeiras 3 linhas na condição else.
Dave Black
8

Para evitar a exceção, você precisa fazer duas coisas:

  1. Adicione um atributo à classe serializada (espero que você tenha acesso)
  2. Gere o arquivo de serialização com sgen.exe

Adicione o atributo System.Xml.Serialization.XmlSerializerAssembly à sua classe. Substitua 'MyAssembly' pelo nome do assembly em que MyClass está.

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

}

Gere o arquivo de serialização usando o utilitário sgen.exe e implante-o com o assembly da classe.

'sgen.exe MyAssembly.dll' gerará o arquivo MyAssembly.XmlSerializers.dll

Essas duas alterações farão com que o .net encontre diretamente o assembly. Eu verifiquei e funciona no .NET framework 3.5 com Visual Studio 2008

Ami Bar
fonte
Ok, e falhou sem essas mudanças? Se sim, por quê?
John Saunders
11
Não encontro motivo para o meu projeto, 4.0 no VS2012, começar a falhar repentinamente. "Ignorar" o erro não era uma opção, porque ocorria toda vez que eu tentava acessar o Active Directory; assim, ignorar significaria não se autenticar. Ainda estou muito frustrado que o VS2012 não gere automaticamente a DLL de serialização corretamente. No entanto, essas etapas forneceram a solução perfeita.
sfuqua
6

Essa exceção também pode ser interceptada por um assistente de depuração gerenciada (MDA) chamado BindingFailure.

Esse MDA é útil se seu aplicativo for projetado para ser fornecido com conjuntos de serialização pré-compilados. Fazemos isso para aumentar o desempenho de nosso aplicativo. Isso nos permite garantir que os conjuntos de serialização pré-criados estejam sendo construídos adequadamente pelo nosso processo de criação e carregados pelo aplicativo sem serem recriados em tempo real.

Realmente não é útil, exceto neste cenário, porque, como outros pôsteres disseram, quando um erro de ligação é capturado pelo construtor Serializer, o conjunto de serialização é recriado em tempo de execução. Então você geralmente pode desligá-lo.

HiredMind
fonte
6

A função XmlSerializer.FromTypes não lança a exceção, mas vaza a memória. É por isso que você precisa armazenar em cache esse serializador para todos os tipos, para evitar vazamento de memória em todas as instâncias criadas.

Crie sua própria fábrica XmlSerializer e use-a simplesmente:

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

A fábrica se parece com:

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

Versão mais complicada sem possibilidade de vazamento de memória (por favor, alguém reveja o código):

    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
fonte
Você deve usar o ConcurrentDictionary. Este código pode entrar em conflito.
precisa
Como ele pode travar se todo o gerenciamento com dicionário estiver na seção de bloqueio?
Tomas Kubes
Desculpe, confundi as palavras. O que eu quis dizer é que ele pode inserir um item mais de uma vez. porque existe uma lacuna entre quando verifica a existência e quando é inserida. o dicionário simultâneo usa algum tipo de bloqueio bifásico (bolsa [0] e bolsa [hash]]) e mantém uma referência à bolsa que deve inserir / conter o item em que você está trabalhando. É mais rápido, seguro e limpo.
precisa
Sim e não. Você está certo que pode acontecer que, ao mesmo tempo, um serializador do mesmo tipo seja criado em dois threads em paralelo e depois adicionado ao dicionário duas vezes. Nesse caso, o segundo inserto substituirá apenas o primeiro, mas a seção de trava garante a segurança da rosca e a desvantagem geral é o pequeno vazamento de memória. Isso é otimização de desempenho, porque você não deseja que o thread um com o serializador do tipo A aguarde seja bloqueado pelo thread dois com o serializador do tipo B no cenário real.
Tomas Kubes
Eu posso imaginar que a solução pode ser ainda melhor (sem vazamento de memória teórica), mas mais complicada.
Tomas Kubes
3

A solução de problemas de erros de compilação, por outro lado, é muito complicada. Esses problemas se manifestam em um FileNotFoundException com a mensagem:

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

Você pode se perguntar o que um arquivo não encontrado tem a ver com instanciar um objeto serializador, mas lembre-se: o construtor grava arquivos C # e tenta compilá-los. A pilha de chamadas dessa exceção fornece algumas informações boas para apoiar essa suspeita. A exceção ocorreu enquanto o XmlSerializer tentou carregar um assembly gerado pelo CodeDOM chamando o método System.Reflection.Assembly.Load. A exceção não fornece uma explicação sobre o motivo pelo qual o assembly que o XmlSerializer deveria criar não estava presente. Em geral, o assembly não está presente porque a compilação falhou, o que pode acontecer porque, em raras circunstâncias, os atributos de serialização produzem código que o compilador C # falha ao compilar.

Nota Este erro também ocorre quando o XmlSerializer é executado em uma conta ou em um ambiente de segurança que não pode acessar o diretório temporário.

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

Zyphrax
fonte
ele não especificou que isso aconteceu em tempo de execução. Outra coisa em que consigo pensar é que você talvez tenha um conflito de namespace / classe. Qual é o nome completo do seu MyType?
Zyphrax 14/07/2009
Sim, eu verifiquei o link do ur, as informações sobre os construtores, embora úteis, não eram o que eu precisava.
Irwin
5
@ SpaceghostAl Você pode compilar em tempo de execução. E é isso que o XmlSerializer faz. Constrói dinamicamente em tempo de execução um assembly que (des) serializa XML para o tipo específico. Por qualquer motivo, esse processo falha no OP. Provavelmente devido a problemas de permissão, por exemplo, em um diretório temporário. (Poderia ser tão bobo como fora do espaço em disco mesmo.)
nºs
Você tem certeza disso? Eu tinha certeza de que o material de serialização é compilado em um assembly com o nome YourAssemblyName.XmlSerializers.dll durante a compilação , não compilado em tempo de execução. Isso pode falhar por todos os tipos de motivos, menos pelas permissões NTFS na pasta de implantação.
tomfanning
11
Eu gostaria de poder votar isso várias vezes. Sua observação sobre a conta de não poder acessar a pasta temporária acionou a resposta para mim. Depois de adicionar minha conta de serviço ao grupo de administradores no servidor, tudo funcionou. Obrigado!
Bob Horn
2

Nas propriedades do projeto do Visual Studio, há uma opção dizendo "gerar assembly de serialização". Tente ativá-lo para um projeto que gera [Contendo Assembly do MyType].

Pascal
fonte
1

Uma classe personalizada para serializar:

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

Anexei o trecho de código. Talvez isso possa ajudá-lo.

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
fonte
2
-1 para não usar blocos para evitar vazamentos de recursos e para usar XmlTextWriter.
317 John Saunders
ok, concordo, mas ainda assim eu usei XmlSerializer xmlSerializer = new XmlSerializer (typeof (TestClass)); mas não estou recebendo a referida exceção.
31510 shahjapan
1

Eu estava tendo um problema semelhante e ignorar a exceção não funcionou para mim. Meu código estava chamando a configuração do NServiceBus 'Configure.With(...).XmlSerializer()...

O que o corrigiu para mim foi mudar a plataforma do meu projeto.

  1. Vá para Build \ Configuration Manager ...
  2. Encontre seu projeto e mude a Plataforma (no meu caso, de x86 para Qualquer CPU)
kkelley
fonte
1

Apenas como referência. Retirando da resposta e dos comentários do DB, eu vim com esta solução que é próxima da solução do DB. Funciona bem em todos os meus casos e é seguro para threads. Eu não acho que o uso de um ConcurrentDictionary tivesse sido bom.

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);
                }
            }
        }
Eric Ouellet
fonte
0

Seu tipo pode fazer referência a outros assemblies que não podem ser encontrados nem no GAC nem na pasta bin local ==> ...

"ou uma de suas dependências. O sistema não pode encontrar o arquivo especificado"

Você pode dar um exemplo do tipo que deseja serializar?

Nota: Verifique se o seu tipo implementa Serializable.

Henrik
fonte
0

Eu estava recebendo o mesmo erro e era devido ao tipo que estava tentando desserializar por não ter um construtor sem parâmetros padrão . Eu adicionei um construtor e ele começou a funcionar.

kay.one
fonte
0

Eu tive o mesmo problema até usar uma ferramenta de terceiros para gerar a classe a partir do XSD e funcionou! Eu descobri que a ferramenta estava adicionando algum código extra na parte superior da minha classe. Quando adicionei esse mesmo código ao topo da minha classe original, ele funcionou. Aqui está o que eu adicionei ...

#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
fonte
0

Visto muitas recomendações para usar um ConcurrentDictionary, mas não há exemplos sólidos, então vou jogar meu chapéu nessa corrida de soluções. Como não sou desenvolvedor de thread-safe, se esse código não for sólido, fale por aqueles que seguem a seguir.

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

Vi outras postagens envolvendo ConcurrentDictionarye Lazycarregando o valor. Não tenho certeza se isso é relevante aqui ou não, mas aqui está o código para isso:

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
fonte