29


6

ApplicationSettingsBaseのFileNotFoundException

アプリケーションをデバッグするときに、Visual Studioで例外ブレークが有効になっていると、常に次のエラーが表示されます。 私たちは例外のブレークで作業しているので、これは本当に私を悩ませています。 おもしろいのは、続行したときにまだ機能することです(StringCollectionが読み込まれます)。

メッセージは次のとおりです。

ファイルまたはアセンブリ「System.XmlSerializers、Version = 4.0.0.0、Culture = neutral、PublicKeyToken = b77a5c561934e089」またはその依存関係の1つをロードできませんでした。 システムは、指定されたファイルを見つけることができません。

例外の原因となっているコードは次のとおりです(デザイナーが生成)

[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Collections.Specialized.StringCollection Mru {
        get {
            return ((global::System.Collections.Specialized.StringCollection)(this["Mru"]));
        }
        set {
            this["Mru"] = value;
        }
    }

エラーを表示する空のテストアプリケーションを作成しようとしましたが、例外は発生しませんでした。 私たちのプロジェクトは巨大なので、原因を見つけるのは難しいです。 このサイトの誰かがこれを解決する手がかりを持っているかもしれません。

3 Answer


54


この例外がスローされる理由の説明。 このサンプルWindows Formsアプリで例外を再現できます。 タイプStringCollectionの「Setting」という名前の設定を追加することから始めます。 [値]列のドットをクリックして、いくつかの文字列を入力します。 フォームクラスコードを次のようにします。

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
    }
    protected override void OnFormClosing(FormClosingEventArgs e) {
        Properties.Settings.Default.Setting[0] = DateTime.Now.ToString();
        Properties.Settings.Default.Save();
        base.OnFormClosing(e);
    }
}

デバッグ+例外、CLR例外の[スロー]チェックボックスをオンにします。 フォームを実行して閉じると、例外がスローされるとデバッガーが停止します。 呼び出しスタックの上部は次のようになります。

mscorlib.dll!System.Reflection.Assembly.nLoad(System.Reflection.AssemblyName fileName, string codeBase, System.Security.Policy.Evidence assemblySecurity, System.Reflection.Assembly locationHint, ref System.Threading.StackCrawlMark stackMark, bool throwOnFileNotFound, bool forIntrospection) + 0x2c bytes
mscorlib.dll!System.Reflection.Assembly.InternalLoad(System.Reflection.AssemblyName assemblyRef, System.Security.Policy.Evidence assemblySecurity, ref System.Threading.StackCrawlMark stackMark, bool forIntrospection) + 0x80 bytes
mscorlib.dll!System.Reflection.Assembly.Load(System.Reflection.AssemblyName assemblyRef) + 0x1d bytes
System.Xml.dll!System.Xml.Serialization.TempAssembly.LoadGeneratedAssembly(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null, out System.Xml.Serialization.XmlSerializerImplementation contract = null) + 0xcd bytes
System.Xml.dll!System.Xml.Serialization.XmlSerializer.XmlSerializer(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null) + 0x105 bytes

StringCollectionクラスのXMLシリアライザーを含むアセンブリを探すXmlSerializerクラスを見ることができます。 LoadGeneratedAssemblyメソッドは、退屈なビットを削除した次のようになります。

internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract)
{
    ...
    AssemblyName parent = GetName(type.Assembly, true);
    partialName = Compiler.GetTempAssemblyName(parent, defaultNamespace);
    parent.Name = partialName;
    parent.CodeBase = null;
    parent.CultureInfo = CultureInfo.InvariantCulture;
    try
    {
        serializer = Assembly.Load(parent);      // <=== here
    }
    catch (Exception exception)
    {
      ...
    }
  ....
}

そして、Compiler.GetTempAssemblyName():

internal static string GetTempAssemblyName(AssemblyName parent, string ns)
{
    return (parent.Name + ".XmlSerializers" + (((ns == null) || (ns.Length == 0)) ? "" : ("." + ns.GetHashCode())));
}

この場合、このGetTempAssemblyNameは悪人です。 StringCollectionクラスはSystem.dllアセンブリに存在し、メソッドは「System.XmlSerializers」という名前を生成します。 このメソッドは、Sgen.exeによって生成された独自のクラスのアセンブリを見つけるように設計されています。 サンプルプログラムのWindowsApplication1.XmlSerializers.dllのように。 ただし、StringCollectionは.NET Frameworkのクラスであり、生成されるアセンブリ名は無効です。 フレームワークには、実際には「System.XmlSerializers.dll」アセンブリはありません。

connect.microsoft.comでのこの動作に関するフィードバックレポートは、すべて「設計」で閉じられています。 元の設計者は、例外を防ぐコストが高すぎると考え、例外をキャッチすることにしました。 すべて正常に動作しますが、例外は実際にキャッチされます。 「デバッグ+例外」ダイアログで「スロー」チェックボックスがオンになっているため、たまたま表示されています。

ここでは、Xmlシリアル化コードの動作を変更することはオプションではありません。 System.dllアセンブリの型を単純に除外することは簡単でしたが、それは終わりのない戦いであり、フレームワークにはさらに多くのアセンブリがあります。 回避策は、StringCollectionを使用する代わりに、独自のクラスを使用して設定を保存することです。


6


これは実際には通常の操作の一部のようです(https://stackoverflow.com/questions/1127431/xmlserializer-giving-filenotfoundexception-at-constructor [コンストラクターでFileNotFoundExceptionを与えるXmlSerializer]も参照)、2つしか提供できません回避策:

この特定の例外を無効にします。[デバッグ/例外]に移動し、[追加]をクリックします。タイプ:C ++例外、名前:EEFileLoadException(表示されている例外の場合)、この例外の[スロー]チェックボックスをオフにします。

設定のタイプを文字列に変更し、アクセスします。 そのようです:

var mru = Settings.Default.Mru.Split('|');
Settings.Default.Mru = string.Join("|", mru.ToArray());


1


あまりにも多くの例外をキャッチしているため、System.XmlSerializerは常に通常の操作の一部としてこの例外をスローし、クラス自体によってキャッチおよび処理されます。 デバッグオプションを変更して、.netファームワーククラス内でキャッチおよび処理される例外ではなく、例外のみをキャッチします。