Reputation: 1661
I've seen couple of similar questions but none resolved my problem. The scenario is - i have couple of DLLs in external storage, i need to get the info about them(Assembly version and AssemblyInformationalVersion to be specific). I started with following code:
List<byte[]> assemblies = _client.DownloadAllAssemblies();
foreach(var assemblyBytes in assemblies)
{
var assembly = Assembly.ReflectionOnlyLoad(assemblyBytes);
var assemblyName = assembly.GetName();
... // read version from assembly name
}
Above code works only one time. If i click a button to refresh the view - it throws exception saying that assembly is already loaded and can't reload it. Then i read that i should create temporary domain and load assemblies into it so i can unload the AppDomain after I'm done. I tried following code:
List<byte[]> assemblies = _client.DownloadAllAssemblies();
var tempDomain = AppDomain.Create("TemporaryDomain");
foreach(var assemblyBytes in assemblies)
{
var assembly = tempDomain.Load(assemblyBytes);
var assemblyName = assembly.GetName();
... // read version from assembly name
}
AppDomain.Unload(tempDomain);
Above code throws FileNotFound exception saying "Cannot load file or assembly ..."
I understand why it is happening but i have no idea how to workaround this. The task seems very trivial:
Nothing complicated in above logic. Seems like overcomplicated by runtime requirements. Does anyone know how can i make it work ?
Upvotes: 3
Views: 1254
Reputation: 9595
Task is not trivial as it seems. AppDomain.Load method is not intended to use it that way.
The Load method of the System.AppDomain class can load assemblies, but is primarily used for COM interoperability. It should not be used to load assemblies into an application domain other than the application domain from which it is called.
I see two solutions to your case:
Simple way. Write assembly bytes array to temporary file, and read its FileVersion
and ProductVersion
via FileVersionInfo.GetVersionInfo. These values in most cases should be the same as in AssemblyVersion
and AssemblyInformalVersion
.
Correct way using AppDomain
. The problem with app domain, is that assemblies you want to load, should be loaded from inside of that domain, not outside.
To achieve this, you need to create special class that contains all necessary logic and that class should be marshalled by reference (inherit it from MarshalByRef class).
Then, after creating new domain, you should load that class inside newly created domain and unwrap it. You can do this with CreateInstanceAndUnwrap method.
This class will live in another domain, and all calls to its methods and properties will be marshalled to that domain, so you can use your logic to load assemblies and read necessary information. Or do any other stuff inside other domain.
When done you can and should unload that domain.
Do not forget, that initially app domain is completely empty, so when you creating instance of any class or load additional assemblies .net should resolve and load all related assemblies into that domain. Sometimes system is unable to do this automatically, but in this case, you can help system do this by subscribing to new domain's AssemblyResolve event.
Upvotes: 3