AppDomain.CurrentDomain.AssemblyResolve запрашивает сборку <AppName>.resources?
Использование кода Как встроить спутниковую сборку в 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;
}
2 ответа
Отвечаю самостоятельно;
Добавление этой строки в AssemblyInfo.cs решает ее, и распознаватель больше не будет запрашивать ресурсы.
[assembly: NeutralResourcesLanguageAttribute("en-US", UltimateResourceFallbackLocation.MainAssembly)]
Хотя это обходной путь, следует внимательно рассмотреть многоязычные приложения.
Больше информации:
- https://connect.microsoft.com/VisualStudio/feedback/details/526836/wpf-appdomain-assemblyresolve-being-called-when-it-shouldnt
- http://blogs.msdn.com/b/kimhamil/archive/2008/11/11/what-does-the-neutralresourceslanguageattribute-do.aspx
- http://forums.devshed.com/net-development-87/c-wpf-appdomain-assemblyresolve-being-called-when-it-shouldn-t-669567.html
- http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx
Этот подход не подходит для машин с не-американской культурой. Лучшим подходом является игнорирование ресурсов в решателе сборок;
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'.
Важной информацией является следующее:
Начиная с.NET Framework 4, событие ResolveEventHandler возникает для всех сборок, включая сборки ресурсов. Смотрите следующую ссылку
https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve(v=vs.110).aspx
Решение оказалось очень простым. Если файл ресурса запрашивается в форме 'dllname.resources.dll', всегда возвращайте ноль;
Вот код события, который я адаптировал из других найденных примеров. (Я прокомментировал строки отладки - откомментируйте их, если у вас есть проблемы с использованием кода.
Добавьте эту строку в ваш класс. Используется для предотвращения загрузки 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;
}