アセンブリの解決に問題があり、それが私を苦労させています。異なるバージョンのアセンブリを解決する
私の会社の製品は、多くのプラグインサービスを持つことができます。私のチームはこれらのサービスに取り組んでいます。ユーティリティアセンブリ(Utility.dll)には、再利用可能なコードがたくさんあります。
時々、私たちはUtility.dllに改善や新機能の追加を行っています。私たちは非常に厳しい下位互換性テストを行って、新しいバージョンのアセンブリが古いプラグインサービスすべてで動作することを確認します。
私が抱えている問題は、現在展開されているバージョンのUtility.dllを解決することです。
例を挙げておきます。
Utility.dllは現在、バージョン1.0.0.0
で我々は、その後Utility.dllを更新し、2.0にバージョンを更新Utility.dllバージョン1.0.0.0
を参照することにより構築されたサービスのサービスAを作成しています。 0.0
次に、Utility.dll 2.0.0.0を使用するサービスServiceBを作成します。
Utility.dllバージョン2.0.0.0は、ServiceAとServiceBの両方と互換性があります。
私はアプリケーションを起動します。展開されたバージョンのUtility.dllが読み込まれます。
私はServiceBを起動します。 AppDomain.CurrentDomain.AssemblyResolveイベントの実装が開始され、Utility.dll 2.0.0.0が返されます。
次に、ServiceAを起動します。 AppDomain.CurrentDomain.AssemblyResolveは決して解雇されませんが、私はUtility.dll 1.0.0.0のFileNotFoundExceptionを取得します。この時点で、私はUtility 2.0.0.0で解決したいと思います。バージョン1.0.0.0が見つからない場合、なぜAssemblyResolveイベントが発生しないのですか?
また、ServiceAを先に起動すると、AssemblyResolveが起動し、Utilty.dll 2.0.0.0がServiceA(これはUtilty.dll 1.0.0.0で作成されたもの)で解決されます。ただし、ServiceB(Utilty.dll 2.0.0.0でビルドされた)を起動すると、AssemblyResolveイベントが発生することはなく、Utility.dllバージョン1.0.0.0に対してFileNotFoundExceptionがスローされます。
何が起こっていますか?私は、現在展開されているバージョンのUtility.dllをすべてのサービスに使用したいだけです。
私はその後、私のサービスの各プラグインでこのようにそれを呼び出しています
public class UtilityLoader
{
private IServiceContext context;
public UtilityLoader(IServiceContext context)
{
this.context = context;
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private bool Loaded
{
get
{
context.Application.Log.WriteInfo("Checking for Utility...");
Assembly asmFound = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(asm => asm.FullName.Contains("Utility"));
context.Application.Log.WriteInfo(string.Format("Utility {0} loaded.{1}", asmFound == null ? "is not" : "is", asmFound == null ? string.Empty : string.Format(" Version: {0}", asmFound.GetName().Version)));
return asmFound != null;
}
}
public bool Load()
{
if (Loaded)
return true;
string utilityPath = Path.Combine(Session.DataDirectory, "Utility.dll");
if (File.Exists(utilityPath))
{
context.Application.Log.WriteInfo(string.Format("Utility.dll was found."));
FileStream stream = File.OpenRead(utilityPath);
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
stream.Close();
try
{
Assembly.Load(assemblyData);
}
catch (Exception ex)
{
context.Application.Log.WriteInfo(string.Format("Could not load Utility: {0}", ex.Message));
throw;
}
return true;
}
return false;
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
AssemblyName asmName = new AssemblyName(args.Name);
if (asmName.Name == "Utility")
{
context.Application.Log.WriteInfo("Resolving Utility");
Assembly nuAsm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(asm => asm.FullName.Contains("Utility"));
context.Application.Log.WriteInfo(string.Format("Utility {0} already loaded.", nuAsm == null ? "is not" : "is"));
return nuAsm;
}
return null;
}
}
****** ******更新しました。
public void Execute(IServiceContext context, ServiceParameters serviceParams)
{
UtilityLoader loader = new UtilityLoader(context);
if (!loader.Load())
{
MessageBox.Show("Utility not loaded.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
StartService(context, serviceParams);
}
と呼ばれる負荷罰金だけでなく、ロードされた最初のサービスプラグインとしてUtility.dllの同じバージョンを参照して構築された任意の他のサービスのプラグインを取得する最初のサービスプラグイン。 Utility.dllの異なるバージョンで構築されたサービスプラグインが呼び出された場合、FileLoadExceptionがスローされます。ユーティリティ1.0.0で構築されたユーティリティ1.0.0.0 ServiceBで構築された
別の例
SERVICEA。0 ユーティリティ2.0.0.0で構築されたServiceB
ユーティリティ2.0.0.0がデプロイされています。
ユーザーが最初にServiceAを起動します。 Utility 2.0.0.0がロードされます。 AssemblyResolveイベントが発生します。アセンブリが解決されました。サービスが開始されます。
ユーザーは、同じセッション内でServiceBを起動します。サービスBはServiceAと同じバージョンのユーティリティを使用します。サービスBが開始されます。
ユーザーは、同じセッション内でServiceCを起動します。 ServiceCは異なるバージョンのユーティリティで構築されました。 ServiceCが読み込まれません。
ユーザーがアプリケーションを再起動し、ServiceCを最初にロードしようとします。 ServiceCは正常に読み込まれます。その後、同じセッション内で、ユーザーはServiceAまたはServiceBの貸し出しを試み、両方が失敗します。
何らかの理由で、サービスが最初のサービスの後に読み込まれると、実際にアセンブリを解決できない場合でも、AssemblyResolveが再び呼び出されません。イベントが発生した場合、ハンドラは現在ロードされているユーティリティのバージョンを返します。
あなたのプロジェクトの構成を正確に見ることなく、何が起こっているのかを確かめることは不可能です。 Utility.dllのリファレンスで「特定のバージョン」が「true」に設定されているサービス(または少なくともServiceA)をコンパイルしたばかりのようです。あなたは、参照されているものと同じか、それより新しいバージョンであれば、存在するバージョンを使用することができます。これらは便利です:https://stackoverflow.com/questions/37431249/whats-the-recommended-way-to-run-plugins-with-dependency-dlls-that-have-differおよびhttps:// stackoverflow。 com/questions/93455/assembly-names-and- –
「特定のバージョン」の設定が最初に見たものです。すべてが "false"に設定されています。 – James
複数のバージョンを読み込むことができます(GACにすべて入れた場合を除いて、別の場所から手作業でインストールする可能性があります)か、親アプリケーションのアセンブリリダイレクトを最高バージョンにするよりも、アセンブリに署名(厳密に名前が付けられています) –