Как загрузить сборку .NET для операций отражения и впоследствии выгрузить ее?
Я пишу инструмент для сообщения информации о приложениях .NET, развернутых в средах и регионах моих клиентских систем.
Я хотел бы прочитать значения атрибутов сборки в этих сборках.
Это может быть достигнуто с помощью Assembly.ReflectionOnlyLoad
, однако даже этот подход позволяет загружать сборку. Проблема здесь в том, что я не могу загрузить две сборки, которые имеют одинаковое имя из разных путей, поэтому, естественно, я не могу сравнивать одно и то же приложение, развернутое в разных системах.
В этот момент я предполагаю, что решение будет включать использование временных AppDomain
s.
Может ли кто-нибудь описать, как загрузить сборку в другую AppDomain
, прочитать атрибуты из нее и затем выгрузить AppDomain
?
Это необходимо для сборки в файловой системе, а также в URL-адресах.
Ответы
Ответ 1
Из Документация MSDN для System.Reflection.Assembly.ReflectionOnlyLoad(String):
Контекст только для отражения отличается от других контекстов. Сборка, загружаемая в контекст может быть выгружен только выгружая домен приложения.
Итак, я боюсь, что единственный способ разгрузить сборку - это выгрузка домена приложения.
Чтобы создать новый AppDomain и загрузить в него сборки:
public void TempLoadAssembly()
{
AppDomain tempDomain = AppDomain.CreateDomain("TemporaryAppDomain");
tempDomain.DoCallBack(LoaderCallback);
AppDomain.Unload(tempDomain);
}
private void LoaderCallback()
{
Assembly.ReflectionOnlyLoad("YourAssembly");
// Do your stuff here
}
Ответ 2
Хотя вы не собираетесь разгружать сборки, если вы просто пытаетесь получить номер версии файла, вы можете использовать System.Diagnostics.FileVersionInfo
.
var info = FileVersionInfo.GetVersionInfo(path);
FileVersionInfo
обладает следующими свойствами:
public string Comments { get; }
public string CompanyName { get; }
public int FileBuildPart { get; }
public string FileDescription { get; }
public int FileMajorPart { get; }
public int FileMinorPart { get; }
public string FileName { get; }
public int FilePrivatePart { get; }
public string FileVersion { get; }
public string InternalName { get; }
public bool IsDebug { get; }
public bool IsPatched { get; }
public bool IsPreRelease { get; }
public bool IsPrivateBuild { get; }
public bool IsSpecialBuild { get; }
public string Language { get; }
public string LegalCopyright { get; }
public string LegalTrademarks { get; }
public string OriginalFilename { get; }
public string PrivateBuild { get; }
public int ProductBuildPart { get; }
public int ProductMajorPart { get; }
public int ProductMinorPart { get; }
public string ProductName { get; }
public int ProductPrivatePart { get; }
public string ProductVersion { get; }
public string SpecialBuild { get; }
Ответ 3
Вы можете попытаться использовать Unmanaged API метаданных, который является COM и может быть легко использован из приложения .NET с какой-то оболочкой.
Ответ 4
Вы должны использовать домены приложений, нет другого способа выгрузить сборку. В основном вы должны использовать такой код:
AppDomain tempDomain = AppDomain.CreateDomain("Temp Domain");
tempDomain.Load(assembly);
AppDomain.Unload(tempDomain);
Ответ 5
Вы можете создать экземпляр в новом AppDomain и выполнить свой код в этом экземпляре.
var settings = new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
};
var childDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, settings);
var handle = Activator.CreateInstance(childDomain,
typeof(ReferenceLoader).Assembly.FullName,
typeof(ReferenceLoader).FullName,
false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, null, CultureInfo.CurrentCulture, new object[0]);
var loader = (ReferenceLoader)handle.Unwrap();
//This operation is executed in the new AppDomain
var paths = loader.LoadReferences(assemblyPath);
AppDomain.Unload(childDomain);
Вот ReferenceLoader
public class ReferenceLoader : MarshalByRefObject
{
public string[] LoadReferences(string assemblyPath)
{
var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
var paths = assembly.GetReferencedAssemblies().Select(x => x.FullName).ToArray();
return paths;
}
}