7

この質問に従って、開発中のレガシー C# アプリでカスタム設定プロバイダーを正常に作成しました。SettingsProvider次の属性を介して参照されます。

public sealed class MySettings : SettingsProvider
{
    ...
}

[SettingsProvider(typeof(MySettings))]
internal sealed partial class Settings {}

しかし、今、私は別の問題に遭遇しました。

クライアント アプリには自動更新機能が含まれており、上記のクラスを含むクライアントの大部分が DLL (ここではclient.dllと呼びましょう) に組み込まれ、EXE によって使用されるように実装されています。EXE は最初に更新をチェックし、必要に応じて更新サーバーから最新の更新をダウンロードし、すべての DLL などを新しいバージョン ( client.dllを含む) に置き換えます。実行時に DLL を置き換えることができるようにするために、DLL に静的にリンクすることはできません。したがって、更新後、client.dllをロードして、次のように実行します。

Assembly assy = Assembly.LoadFile(
        AppDomain.CurrentDomain.BaseDirectory + "client.dll");
object frm = assy.CreateInstance("Client.Forms.MainForm");
Application.Run((Form)frm);

これの残念な結果は、動的に読み込まれたアセンブリ内でフレームワークがカスタム設定プロバイダー クラスを見つけられないことです。LoadFrom上記の代わりに使用しようとしましLoadFileたが、役に立ちませんでした。私がこれまでに見つけた唯一の実用的な解決策は、フレームワークによって問題なく検出された実際の設定プロバイダーと同じ名前のローダー exe にプロキシ クラスを実装することです。次に、プロキシはクライアント アセンブリから実際の設定プロバイダーをインスタンス化し、すべての呼び出しを委任します。

これはうまくいくようですが、私はそれに満足していません。フレームワークが動的に読み込まれたアセンブリ内のクラスを直接見つけるのを助ける方法はありますか?

アップデート

私が得るエラーメッセージ:

System.Configuration.ConfigurationErrorsException: Failed to load provider type: Client.Properties.MySettings, Client, Version=4.0.1341.0, Culture=neutral, PublicKeyToken=null.
   at System.Configuration.ApplicationSettingsBase.get_Initializer()
   at System.Configuration.ApplicationSettingsBase.CreateSetting(PropertyInfo propInfo)
   at System.Configuration.ApplicationSettingsBase.EnsureInitialized()
   at System.Configuration.ApplicationSettingsBase.get_Properties()
   at System.Configuration.SettingsBase.GetPropertyValueByName(String propertyName)
   at System.Configuration.SettingsBase.get_Item(String propertyName)
   at System.Configuration.ApplicationSettingsBase.GetPropertyValue(String propertyName)
   at System.Configuration.ApplicationSettingsBase.get_Item(String propertyName)
   at Client.Properties.Settings.get_SomeConfigSetting()
   at ...

デバッグとログ メッセージを介して、クラスの初期化メソッドが呼び出されないことが判明したため、クラスがインスタンス化されることはありません。つまり、上記の例外の背後に隠された初期化エラーはないようです。

もう 1 つ潜在的に重要なこと: クライアントは現在 .NET 2.0 で実行されており、近い将来にアップグレードする予定はありません。

更新 2

@jwddixonの回答で示唆されているように、AppDomainの調査を開始しました。最初に、Client.dll が実際に呼び出し元の EXE とは異なるアプリ ドメインに配置されているかどうかを確認する必要がありました。そのため、現在のアプリ ドメインにあるアセンブリを一覧表示したところ、Clientが実際にそこにあることがわかりました。しかし驚いたことに、実際にはリストにClientという名前のアセンブリが 2 つあることに気付きました。EXE と DLL のアセンブリ名は同じですが、バージョンが異なります (現在、EXE は 4.0.0.0、DLL は 4.0.1352.0)。 )。私はこれまで十分に認識していませんでしたが、これは重要なことかもしれません。次にEXEアセンブリ名を変更してみます...

アップデート 3

...そして、それは実際に問題を解決しました! ああ...なぜだかわからないこのねじれたスキームを発明した私の未知の前任者に対して、私は現時点で非常に不快な考えを持っています...しかし、最終的に解決につながる質問とアイデアを提供してくれた皆さんに称賛を!

4

1 に答える 1

1

私はこれを試していませんが、次のようなものはどうですか:

AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
AppDomain domain = AppDomain.CreateDomain("myAppDomain", null, setup)
setup.ApplicationBase = file;

Assembly assy = domain.Load(AssemblyName.GetAssemblyName(
AppDomain.CurrentDomain.BaseDirectory +
 "client.dll"));

object frm = assy.CreateInstance("Client.Forms.MainForm");
Application.Run((Form)frm);
于 2013-03-06T10:56:07.497 に答える