我一直在使用的一个应用程序在尝试序列化类型时失败了。

像这样的陈述

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

生产:

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)

我没有为我的类定义任何特殊的序列化器。

我该如何解决这个问题?


当前回答

在我的一个。net标准dll中也有类似的问题。

我使用了Microsoft.XmlSerializer.Generator nuget,它可以在. net Core和. net Standard上预生成XmlSerializer。

其他回答

我的解决方案是直接使用反射来创建序列化器。这就绕过了导致异常的奇怪文件加载。我将其打包在一个helper函数中,该函数还负责缓存序列化器。

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

我也有同样的问题,直到我使用第三方工具从XSD生成类,它工作了!我发现这个工具在类的顶部添加了一些额外的代码。当我把同样的代码添加到我原来的类的顶部时,它起作用了。以下是我添加的内容……

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

另一方面,对编译错误进行故障排除是非常复杂的。这些问题在FileNotFoundException异常中显示,并显示如下信息:

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

You may wonder what a file not found exception has to do with instantiating a serializer object, but remember: the constructor writes C# files and tries to compile them. The call stack of this exception provides some good information to support that suspicion. The exception occurred while the XmlSerializer attempted to load an assembly generated by CodeDOM calling the System.Reflection.Assembly.Load method. The exception does not provide an explanation as to why the assembly that the XmlSerializer was supposed to create was not present. In general, the assembly is not present because the compilation failed, which may happen because, under rare circumstances, the serialization attributes produce code that the C# compiler fails to compile.

请注意 当XmlSerializer在不能访问临时目录的帐户或安全环境下运行时,也会发生此错误。

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

在Visual Studio项目属性(“Build”页面,如果我没记错的话)中有一个选项显示“生成序列化程序集”。尝试为生成[包含MyType的程序集]的项目打开该选项。

只是作为参考。从D-B的回答和评论中,我得出了这个接近D-B的解决方案。它在我的所有情况下都工作得很好,并且是线程安全的。我不认为使用ConcurrentDictionary是可以的。

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

用法:

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