私は2つのプリコンパイルされたDLLを与えられました:
Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL
Common.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL
APIの違いの例:
そして、私は両方を単一のプロジェクトにロードして、次のようなことをしようとしています:
extern alias v10;
extern alias v20;
private static void UpgradeUser()
{
// Load old user
var userOld = new v10::Common.Data.UserData();
userOld.loadData("user.dat");
// Create new user
var userNew = new v20::Common.Data.UserData();
// Copy properties
userNew.FirstName = userOld._firstName;
userNew.LastName = userOld._lastName;
userNew.Age = userOld._age;
// Invoke method from v10 and v20 API
userOld.version();
userNew.DisplayVersion();
if (userNew.GetUserInfo() != userOld.getInfo())
{
throw new Exception("Discrepencies in upgrade ");
}
Console.WriteLine("Upgrade done!");
}
プロジェクト参照とapp.config
を次のように設定しました。また、dllを手動で出力フォルダーにコピーし、appconfig hrefと一致させています
<!-- [Edited: see history for previous version] -->
<Reference Include="Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL">
<HintPath>libs\Common.Data.1_0_0_0.dll</HintPath>
<Aliases>v10</Aliases>
</Reference>
<Reference Include="Common.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL">
<HintPath>libs\Common.Data.2_0_0_0.dll</HintPath>
<Aliases>v20</Aliases>
</Reference>
<runtime>
<assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Common.Data" publicKeyToken="f3b12eb6de839f43" culture="neutral" />
<codeBase version="1.0.0.0" href="libs\Common.Data.1_0_0_0.dll" />
<codeBase version="2.0.0.0" href="libs\Common.Data.2_0_0_0.dll" />
</dependentAssembly>
</assemblyBinding>
</runtime>
ビルドが成功するまでになりました。
しかし、実行しようとすると、UserData.loadData
のMissingMethodException
が返されます。
私は複数のstackoverflowの投稿、msdn、codeprojectの記事を読んできましたが、機能するようには思えません。
私は重要なステップを逃していると思いますが、何を理解できないか、本当に助けを使うことができます。
[Edit1]
Dllを個別に使用してみましたが、動作します。 (混乱を解消。スクリーンショットのバージョン履歴を参照)
[Edit2]
Mukesh Kumarの提案を試し、app.configを次のように変更しました。
<runtime>
<assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Common.Data"
publicKeyToken="f3b12eb6de839f43"
culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0"
newVersion="2.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
しかし、まだ機能しません。 FileNotFoundException
を取得しています。
[Edit3]
OK、<bindingRedirect>
が正しくないことはほぼ確実です。代わりに<codeBase>
にする必要があります。
CLIからコンパイルしてみました:
csc Program.cs /reference:v10=libs/Common.Data.1_0_0_0.dll /reference:v20=libs/Common.Data.2_0_0_0.dll
そしてそれはうまく機能します。両方のAPIを同時に使用できました。
しかし、Visual Studioからビルドしようとすると、既に参照エイリアスを指定しているにもかかわらず、/ referenceについてエラーが発生します。
The extern alias 'v10' was not specified in a /reference option
<Reference />
を変更して、<SpecificVersion>True</SpecificVersion>
を含めたり除外したりしても、何の効果もありません。
私はこれを見つけました post 、解決策はパスを削除して再追加することでした。そのソリューションを使用すると、Visual Studioは正常にビルドされますが、System.MissingMethodException
に戻ります。
私はそれをほとんど手に入れたように感じますが、完全ではありません。 Visual Studioを正しくビルドするにはどうすればよいですか?
[Edit4]
Miguelの方法を試しましたが、まだ動作しません。
この試みでは、dllの名前を元の名前に戻し、代わりに別のフォルダーに保存しました。
その後、app.configを更新してbindingRedirectとコードベースを実行しました。
実行すると、MissingMethodException
が表示されます。
4- Find the and put in False
の意味がわからなかったので、<Private>
、<SpecificVersion>
のすべての組み合わせ、および<Reference Include>
をFQNに設定しようとしましたが、それらの組み合わせは機能しませんでした。
3回目の編集を見て、CLI経由でサンプルをコンパイルし、正常に(名前を変更したdll + app.config codebase hrefを使用して)実行できました。
私の問題は、csprojをどのように構成すればよいのかということです。
BindingRedirectでdependentAssemblyを使用する必要がありますが、別のフォルダーにdllを配置するか、別の名前で保存する必要もあります。これが完了したら、app.configに以下を追加する必要があります。
<assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="here token dll"
culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.0.0" newVersion="1.0.0.0" />
<bindingRedirect oldVersion="1.0.0.1-2.0.0.0" newVersion="2.0.0.0" />
<codeBase version="1.0.0.0" href="folder\namedll.dll" />
<codeBase version="2.0.0.0" href="folder\namedll.dll" />
</dependentAssembly>
</assemblyBinding>
このコードではコンパイルして実行する必要がありますが、VSはコンパイル時にapp.configのコードを削除または上書きする場合があります。編集フォルダーの設定ファイルで確認する必要があります。これが成功した場合、.csprojを編集できます。そのためには、次のことを行う必要があります。
1-影響を受けるプロジェクトをアンロードします
2-プロジェクトを右クリック
3- [プロジェクトの編集]をクリックします
4-<AutoGenerateBindingRedirects>
プロパティを見つけて、Falseに設定します
5-変更を保存してプロジェクトをリロードする
これは私のために動作します。私のプロジェクトでは、Automapperの2つのバージョンを使用しています。
最後に、別の解決策は、AppDomain.CurrentDomain.AssemblyResolve
ビルドイベントを使用して特定のdllをロードすることです。
そのためには、イベントをキャッチする必要があります。
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
public static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//debug and check the name
if (args.Name == "MyDllName")
return Assembly.LoadFrom("c:\\pathdll\midllv1.dll")
else if(args.Name ="MyDllName2")
return Assembly.LoadFrom("c:\\pathdll\midllv2.dll");
else
return Assembly.LoadFrom("");
}
私のニーズに合った完全な答えが見つからないので、タイプを解決するためにリフレクションを使用して、2つのdllを使用して関連するファイルをロードするAssemblyResolve
方法でソリューションを寄付することにしました。このデモでは、MathFuncs
という2つのdllを作成し、Add.add
関数を呼び出そうとすると、2つの異なる実装で解決します。異なる結果を確認するには、バージョン整数を値1と2の間で切り替えます。
public static int version = 1;
public static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += Program.CurrentDomain_AssemblyResolve;
version = 1;
Type a = Type.GetType("MathFuncs.Add, MathFuncs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
MethodInfo methodInfo = a?.GetMethod("add");
object result = null;
if (methodInfo != null)
{
object[] parametersArray = new object[] {1, 2};
result = methodInfo.Invoke(Activator.CreateInstance(a, null), parametersArray);
}
if (result != null)
{
Console.WriteLine((int)result);
}
else
{
Console.WriteLine("failed");
}
Console.Read();
}
public static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
FileInfo fi = null;
if (version == 1)
{
fi = new FileInfo("C:\\Users\\ohbitton\\Desktop\\MathFuncs\\MathFuncs.dll");
}
else
{
fi = new FileInfo("C:\\Users\\ohbitton\\Desktop\\MathFuncs2\\MathFuncs.dll");
}
return Assembly.LoadFrom(fi.FullName);
}
Type.GetType
の名前空間の完全な名前を取得するには、powershellを使用できます。
([system.reflection.Assembly]::loadfile("C:\Users\ohbitton\Desktop\MathFuncs\MathFuncs.dll")).FullName