コードを使用して サテライトアセンブリをEXEファイルに埋め込む方法 csharptest.netによって提供され、カスタムアセンブリリゾルバーを作成し、アセンブリをリソースに埋め込みました。
で使用されているアセンブリを正常に解決できますが、どういうわけかAppDomain.CurrentDomain.AssemblyResolveは、「AppName.resources」、具体的には「MyProgram.resources、Version = 0.15.3992.31638、Culture = en-US、PublicKeyToken = null」というアセンブリを要求します。解決する方法がわかりませんか?
リソースからのカスタムアセンブリの読み込みを無効にしようとし(すべてのアセンブリdllをプログラムディレクトリに配置)、AppDomain.CurrentDomain.AssemblyResolveを有効にしましたが、それでも要求されていました。
私はこれについて少し混乱しています、あなたがこれについて私を助けることができればたくさん感謝します。
これが興味のある人のための私のコードです。
static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string name = args.Name.Substring(0, args.Name.IndexOf(','));
if (name == "MyProgram.resources") return null;
else name = string.Format("MyProgram.Resources.Assemblies.{0}.dll", name);
lock (_loadedAssemblies)
{
if (!_loadedAssemblies.TryGetValue(name, out Assembly))
{
using (Stream io = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
{
if (io == null)
{
MessageBox.Show("MyProgram can not load one of it's dependencies. Please re-install the program", string.Format("Missing Assembly: {0}", name), MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(-1);
}
using (BinaryReader binaryReader = new BinaryReader(io))
{
Assembly = Assembly.Load(binaryReader.ReadBytes((int)io.Length));
_loadedAssemblies.Add(name, Assembly);
}
}
}
}
return Assembly;
}
自分で答える;
この行をAssemblyInfo.csに追加すると解決され、リゾルバーはリソースを要求されなくなります。
[Assembly: NeutralResourcesLanguageAttribute("en-US", UltimateResourceFallbackLocation.MainAssembly)]
これは回避策ですが、多言語アプリケーションを慎重に検討する必要があります。
より詳しい情報:
このアプローチは、米国以外の文化を持つマシンでは失敗します。より良いアプローチは、アセンブリリゾルバのリソースを無視することです。
public Assembly Resolver(object sender, ResolveEventArgs args)
{
lock (this)
{
Assembly assembly;
AssemblyName askedAssembly = new AssemblyName(args.Name);
string[] fields = args.Name.Split(',');
string name = fields[0];
string culture = fields[2];
// failing to ignore queries for satellite resource assemblies or using [Assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)]
// in AssemblyInfo.cs will crash the program on non en-US based system cultures.
if (name.EndsWith(".resources") && !culture.EndsWith("neutral")) return null;
/* the actual Assembly resolver */
...
}
}
私の状況はもう少し複雑で、上記の解決策は私にはうまくいきませんでした。 (これにより、AssemblyInfo.csファイルが変更されます)
すべてのフォームと画像リソースを別のdllに移動しましたが、画像のいずれかが使用されるとすぐに「filenotfoundexception」例外がスローされます。
重要な情報は次のとおりです。
。NETFramework 4以降、リソースアセンブリを含むすべてのアセンブリに対してResolveEventHandlerイベントが発生します。次のリファレンスを参照してください
https://msdn.Microsoft.com/en-us/library/system.appdomain.assemblyresolve(v = vs.110).aspx
解決策は非常に単純であることが判明しました。リソースファイルが「dllname.resources.dll」の形式で要求された場合、常にnullを返します。
これは、見つかった他のサンプルから適応させたイベントコードです。 (デバッグ行にコメントしました。コードの使用に問題がある場合はコメントを外してください。
この行をクラスに追加します。これは、dllが複数回ロードされるのを防ぐために使用されます
readonly static Dictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
これはイベントメソッドです。
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string keyName = new AssemblyName(args.Name).Name;
if (keyName.Contains(".resources"))
{
return null; // This line is what fixed the problem
}
if (_libs.ContainsKey(keyName))
{
Assembly = _libs[keyName]; // If DLL is loaded then don't load it again just return
return Assembly;
}
string dllName = DllResourceName(keyName);
//string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); // Uncomment this line to debug the possible values for dllName
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(dllName))
{
if (stream == null)
{
Debug.Print("Error! Unable to find '" + dllName + "'");
// Uncomment the next lines to show message the moment an Assembly is not found. (This will also stop for .Net assemblies
//MessageBox.Show("Error! Unable to find '" + dllName + "'! Application will terminate.");
//Environment.Exit(0);
return null;
}
byte[] buffer = new BinaryReader(stream).ReadBytes((int) stream.Length);
Assembly = Assembly.Load(buffer);
_libs[keyName] = Assembly;
return Assembly;
}
}
private static string DllResourceName(string ddlName)
{
if (ddlName.Contains(".dll") == false) ddlName += ".dll";
foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if (name.EndsWith(ddlName)) return name;
}
return ddlName;
}