型をシリアル化しようとすると、作業していたアプリケーションが失敗します。
のような声明
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)
クラスには特別なシリアライザーを定義していません。
この問題を修正するにはどうすればよいですか?
信じられないかもしれませんが、これは通常の動作です。例外がスローされますが、XmlSerializerによって処理されるため、それを無視しただけですべてが正常に続行するはずです。
私はこれを非常にいらいらさせており、少し検索するとこれについて多くの苦情がありましたが、私が読んだことから、Microsoftはそれについて何もするつもりはありません。
特定の例外のファーストチャンス例外をオフにすると、デバッグ中に常に例外ポップアップが表示されることを回避できます。 Visual Studioで、Debug->Exceptionsに移動(または押す Ctrl + Alt + E)、共通言語ランタイムの例外->System.IO->System.IO.FileNotFoundException。
ブログの投稿C#XmlSerializer FileNotFound exception(Chris Sell'sツールXmlSerializerPreCompiler)。
Martin Sherburnが言ったように、これは正常な動作です。 XmlSerializerのコンストラクターは、最初に[YourAssembly] .XmlSerializers.dllという名前のアセンブリを見つけようとします。このアセンブリには、型のシリアル化のために生成されたクラスが含まれている必要があります。そのようなDLLはまだ生成されていないため(デフォルトでは生成されません)、FileNotFoundExceptionがスローされます。それが起こると、XmlSerializerのコンストラクターがその例外をキャッチし、DLLが実行時にXmlSerializerのコンストラクターによって自動的に生成されます(これはコンピューターの%temp%ディレクトリーでC#ソースファイルを生成し、それらをコンパイルすることで行われます) C#コンパイラを使用)。同じ型のXmlSerializerの追加の構成では、既に生成されたDLLが使用されます。
UPDATE:.NET 4.5以降、
XmlSerializer
はコード生成を実行せず、実行時にシリアライザーアセンブリを作成するためにC#コンパイラーでコンパイルを実行しません、構成ファイル設定( seLegacySerializerGeneration )を設定して明示的に強制されない限り。この変更により、csc.exe
への依存関係がなくなり、起動パフォーマンスが向上します。 出典: 。NET Framework 4.5 Readme 、セクション1.3.8.1。
例外はXmlSerializerのコンストラクターによって処理されます。自分で何もする必要はありません。[続行](F5)をクリックするだけでプログラムの実行を続けることができ、すべてが正常になります。プログラムの実行を停止し、例外ヘルパーをポップアップする例外に悩まされている場合は、「Just My Code」をオフにするか、「ユーザー-」ではなく「スロー」の実行を中断するようにFileNotFoundExceptionを設定します。未処理」。
「Just My Code」を有効にするには、「ツール」>>「オプション」>>「デバッグ」>>「一般」>>「Just My Code」を選択します。 FileNotFoundがスローされたときに実行の中断をオフにするには、[デバッグ] >> [例外] >> [検索] >> [FileNotFoundException]を入力します>> System.IO.FileNotFoundExceptionから[スロー]チェックボックスをオフにします。
Visual Studioプロジェクトのプロパティ(「ビルド」ページ、私が正しく思い出せば)には、「シリアル化アセンブリを生成する」というオプションがあります。 [MyTypeのアセンブリを含む]を生成するプロジェクトで有効にしてみてください。
そのための回避策があります。使用する場合
XmlSerializer lizer = XmlSerializer.FromTypes(new[] { typeof(MyType) })[0];
その例外を回避する必要があります。これは私のために働いた。
警告:複数回使用しないでください。複数回使用しないでくださいメモリリーク
このメソッドを使用して、同じタイプのXmlSerializer
のインスタンスを複数回作成すると、狂ったようにメモリがリークします!
これは、このメソッドがXmlSerializer(type)
およびXmlSerializer(type, defaultNameSpace)
コンストラクターが提供する組み込みキャッシュをバイパスするためです(他のすべてのコンストラクターもキャッシュをバイパスします)。
これらの2つのコンストラクターを使用しないXmlSerializerを作成するためのメソッドを使用する場合、独自のキャッシュを実装する必要があります。そうしないと、メモリが出血します。
私はこの正確な問題に出くわし、言及された解決策のいずれかによってそれを回避することができませんでした。
それから私は最終的に解決策を見つけました。シリアライザーは型だけでなく、ネストされた型も必要とするようです。これを変更する:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
これに:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T).GetNestedTypes());
私の問題を修正しました。これ以上の例外も何もありません。
私の解決策は、リフレクションに直行してシリアライザーを作成することです。これにより、例外の原因となる奇妙なファイルのロードがバイパスされます。これを、シリアライザーのキャッシュを処理するヘルパー関数にパッケージ化しました。
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つのことを行う必要があります。
System.Xml.Serialization.XmlSerializerAssembly属性をクラスに追加します。 「MyAssembly」をMyClassが含まれているアセンブリの名前に置き換えます。
[Serializable]
[XmlSerializerAssembly("MyAssembly.XmlSerializers")]
public class MyClass
{
…
}
Sgen.exeユーティリティを使用してシリアル化ファイルを生成し、クラスのアセンブリとともに展開します。
「sgen.exe MyAssembly.dll」は、ファイルMyAssembly.XmlSerializers.dllを生成します
これら2つの変更により、.netはアセンブリを直接検索します。私はそれをチェックし、Visual Studio 2008で.NET framework 3.5で動作します
この例外は、BindingFailureと呼ばれる マネージデバッグアシスタント (MDA)によってトラップされることもあります。
このMDAは、アプリケーションがビルド前のシリアル化アセンブリと共に出荷するように設計されている場合に役立ちます。これにより、アプリケーションのパフォーマンスが向上します。これにより、ビルド済みのシリアル化アセンブリがビルドプロセスによって適切にビルドされ、その場で再ビルドされることなくアプリケーションによってロードされることを確認できます。
他の投稿者が言ったように、Serializerコンストラクターによってバインディングエラーがトラップされると、実行時にシリアル化アセンブリが再構築されるため、このシナリオを除いて実際には役に立ちません。そのため、通常はオフにすることができます。
関数XmlSerializer.FromTypesは例外をスローしませんが、メモリをリークします。そのため、作成されたすべてのインスタンスのメモリリークを回避するために、すべてのタイプのこのようなシリアライザーをキャッシュする必要があります。
独自のXmlSerializerファクトリを作成し、単純に使用します。
XmlSerializer serializer = XmlSerializerFactoryNoThrow.Create(typeof(MyType));
工場は次のように見えます:
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;
}
}
メモリリークの可能性のない、より複雑なバージョン(コードをレビューしてください):
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;
}
}
一方、コンパイルエラーのトラブルシューティングは非常に複雑です。これらの問題は、メッセージとともに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()
ファイルが見つからないという例外がシリアライザーオブジェクトのインスタンス化とどう関係するのか疑問に思うかもしれませんが、コンストラクターはC#ファイルを書き込み、それらをコンパイルしようとします。この例外のコールスタックは、その疑いをサポートするための適切な情報を提供します。 XmlSerializerが、System.Reflection.Assembly.Loadメソッドを呼び出すCodeDOMによって生成されたアセンブリをロードしようとしたときに、例外が発生しました。例外は、XmlSerializerが作成することになっているアセンブリが存在しない理由についての説明を提供しません。一般に、コンパイルが失敗したためアセンブリは存在しません。これは、まれに、シリアル化属性がC#コンパイラがコンパイルに失敗するコードを生成するために発生する可能性があります。
注このエラーは、一時ディレクトリにアクセスできないアカウントまたはセキュリティ環境でXmlSerializerが実行されている場合にも発生します。
Visual Studioプロジェクトプロパティには、「シリアル化アセンブリを生成する」というオプションがあります。 [Containing Assembly of MyType]を生成するプロジェクトに対してオンにしてみてください。
私は同様の問題を抱えていましたが、例外を無視してもうまくいきませんでした。私のコードはNServiceBusの構成を呼び出していましたConfigure.With(...).XmlSerializer()...
私にとってそれを修正したのは、プロジェクトのプラットフォームを変更することでした。
シリアル化するカスタムクラス:
[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;
}
}
コードスニペットを添付しました。たぶんこれはあなたを助けることができます。
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();
}
参考として。 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);
}
}
}
サードパーティのツールを使用して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
{
...
ConcurrentDictionary
を使用するための多くの推奨事項がありましたが、その具体的な例はありませんでしたので、このソリューションレースに帽子を投げます。私はスレッドセーフな開発者ではないので、このコードがしっかりしていない場合は、後に続く人のために声を上げてください。
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);
});
}
}
ConcurrentDictionary
およびLazy
が値をロードすることに関する他の投稿を見てきました。それがここに関連するかどうかはわかりませんが、そのためのコードは次のとおりです。
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;
}
タイプは、 GAC でもローカルbinフォルダーでもない他のアセンブリを参照する場合があります==> ...
「またはその依存関係の1つ。指定されたファイルが見つかりません」
シリアル化するタイプの例を教えてください。
注:タイプがSerializableを実装していることを確認してください。
私は同じエラーを受け取っていましたが、それはデフォルトのパラメータなしのコンストラクタを持たないデシリアライズしようとしたタイプによるものでした。コンストラクターを追加すると、機能し始めました。