3

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:

  1. Load file,
  2. Read its version,
  3. Forget about it.

Nothing complicated in above logic. Seems like overcomplicated by runtime requirements. Does anyone know how can i make it work ?

escape-llc
  • 1,295
  • 1
  • 12
  • 25
MajkeloDev
  • 1,661
  • 13
  • 30
  • need more of the stack trace (always supply complete information) it's possible that a dependent assembly could not be loaded before it finished loading whatever byte array you are passing in. there are some properties on `AppDomain` you should copy from the default, like probing path. Also you still want to use `ReflectionOnlyLoad` it will not attempt to resolve everything. – escape-llc Feb 28 '17 at 14:26
  • @escape-llc AppDomain doesn't expose "ReflectionOnlyLoad" function. I will update question with StackTrace later. Thanks. – MajkeloDev Feb 28 '17 at 15:32

1 Answers1

3

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:

  1. 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.

  2. 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.

arbiter
  • 9,447
  • 1
  • 32
  • 43
  • Thanks for response. if "AppDomain.Load method is not intended to use it that way." then i don't want to "missuse" it. I will try the temporary download solution and let you know if success. I have a control over dlls creation(they are created and compiled on the website) so i should be able to set FileVerison so it will equal to AssemblyVersion. – MajkeloDev Mar 01 '17 at 11:59
  • I ended up with steve16351's solution http://stackoverflow.com/questions/26106431/loading-byte-array-assembly-into-new-appdomain-throws-a-filenotfound-exception/26107788?noredirect=1#comment72198604_26107788 – MajkeloDev Mar 02 '17 at 15:00