XmlSerializer giving FileNotFoundException at cons

2019-01-02 19:24发布

An application I've been working with is failing when I try to serialize types.

A statement like

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

produces:

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)

I don't define any special serializers for my class.

How can I fix this problem?

17条回答
高级女魔头
2楼-- · 2019-01-02 20:00

Like Martin Sherburn said, this is normal behavior. The constructor of the XmlSerializer first tries to find an assembly named [YourAssembly].XmlSerializers.dll which should contain the generated class for serialization of your type. Since such a DLL has not been generated yet (they are not by default), a FileNotFoundException is thrown. When that happenes, XmlSerializer's constructor catches that exception, and the DLL is generated automatically at runtime by the XmlSerializer's constructor (this is done by generating C# source files in the %temp% directory of your computer, then compiling them using the C# compiler). Additional constructions of an XmlSerializer for the same type will just use the already generated DLL.

UPDATE: Starting from .NET 4.5, XmlSerializer no longer performs code generation nor does it perform compilation with the C# compiler in order to create a serializer assembly at runtime, unless explicitly forced to by setting a configuration file setting (useLegacySerializerGeneration). This change removes the dependency on csc.exe and improves startup performance. Source: .NET Framework 4.5 Readme, section 1.3.8.1.

The exception is handled by XmlSerializer's constructor. There is no need to do anything yourself, you can just click 'Continue' (F5) to continue executing your program and everything will be fine. If you're bothered by the exceptions stopping the execution of your program and popping up an exception helper, you either have 'Just My Code' turned off, or you have the FileNotFoundException set to break execution when thrown, instead of when 'User-unhandled'.

To enable 'Just My Code', go to Tools >> Options >> Debugging >> General >> Enable Just My Code. To turn off breaking of execution when FileNotFound is thrown, go to Debug >> Exceptions >> Find >> enter 'FileNotFoundException' >> untick the 'Thrown' checkbox from System.IO.FileNotFoundException.

查看更多
残风、尘缘若梦
3楼-- · 2019-01-02 20:03

Function XmlSerializer.FromTypes does not throw the exception, but it leaks the memory. Thats why you need to cache such serializer for every type to avoid memory leaking for every instance created.

Create your own XmlSerializer factory and use it simply:

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

The factory looks likes:

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

More complicated version without possibility of memory leak (please someone review the 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;
    }       
}
查看更多
大哥的爱人
4楼-- · 2019-01-02 20:03

I was having a similar problem, and ignoring the exception did not work for me. My code was calling NServiceBus' configuration Configure.With(...).XmlSerializer()...

What fixed it for me was to change the platform for my project.

  1. Go to Build\Configuration Manager...
  2. Find your project and change Platform (in my case from x86 to Any CPU)
查看更多
看风景的人
5楼-- · 2019-01-02 20:04

Your type may reference other assemblies which cannot be found neither in the GAC nor in your local bin folder ==> ...

"or one of its dependencies. The system cannot find the file specified"

Can you give an example of the type you want to serialize?

Note: Ensure that your type implements Serializable.

查看更多
姐姐魅力值爆表
6楼-- · 2019-01-02 20:06

I ran into this exact issue and couldn't get around it by any of the solutions mentioned.

Then I finally found a solution. It appears that the serializer needs not only the type, but the nested types as well. Changing this:

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

To this:

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

Fixed the issue for me. No more exceptions or anything.

查看更多
春风洒进眼中
7楼-- · 2019-01-02 20:09

To avoid the exception you need to do two things:

  1. Add an attribute to the serialized class (I hope you have access)
  2. Generate the serialization file with sgen.exe

Add the System.Xml.Serialization.XmlSerializerAssembly attribute to your class. Replace 'MyAssembly' with the name of the assembly where MyClass is in.

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

Generate the serialization file using the sgen.exe utility and deploy it with the class’s assembly.

‘sgen.exe MyAssembly.dll’ will generate the file MyAssembly.XmlSerializers.dll

These two changes will cause the .net to directly find the assembly. I checked it and it works on .NET framework 3.5 with Visual Studio 2008

查看更多
登录 后发表回答