Embedded Assembly Resolution in new AppDomain

I am working on an application that uses SmartAssembly to embed all top level dependencies into the resulting application. Currently I am having issues trying to dynamically load "plugin" assemblies that have a dependency on the same top level assemblies.
For Example:
I have a library assembly which essentially contains all my internal business logic. This is a dependency of both the application (so I am able to load my custom "plugins") and the plugins themselves.
Due the need to filter loaded plugins, I am using a new AppDoamin in which to load them and retrieve their "metadata". This cannot be done using the reflectionOnly context as I am using that already for something else.
When I deploy my application, it loads fine until it gets to reading the plugin "metadata".
I am wondering if there is a way for me to pass the SmartAssembly resolver into my new AppDomain, such that my plugin can load it's dependencies from the application resources?

Application.exe
- library.dll

Plugin.plg (*.dll)
- library.dll

Any help would be greatly appreciated.
Tagged:

Answers

  • Alex BAlex B Posts: 1,157 Diamond 4
    Hi @Izzyonstage,

    I think this is a fundamental limitation of embedding, but I'm going to double check with the developers to confirm that and I will  come back to you!

    Kind regards,
    Alex
    Product Support Engineer | Redgate Software

    Have you visited our Help Center?
  • IzzyonstageIzzyonstage Posts: 5 New member
    If there was a way from within the assembly to inject a class that enables me to request an embedded assembly, then I could do something like:
    private static Assembly Internal_Resolve(object sender, ResolveEventArgs args) {<br>&nbsp; &nbsp; // ... initial resolver setup<br><br>&nbsp; &nbsp; // ... mainDomain is the required Assembly's AppDomain<br>&nbsp; &nbsp; // ... saResolverTypeName is the SA resolver class FullName (passed in to AppDomain Initializer)<br>&nbsp; &nbsp; // ... saResolverPath is SA resolver class location (passed in to AppDomain Initializer);<br>&nbsp; &nbsp; //&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;discovered using typeof(...).Assembly.Location<br>&nbsp; &nbsp; var parentResolver = mainDomain.CreateInstanceFromAndUnwrap(saResolverPath, saResolverTypeName);<br>&nbsp; &nbsp; parentResolver.ResourceAssembly = typeof(CallingAssemblyType).Assembly;<br>&nbsp; &nbsp; var asm = parentResolver.Resolve(sender, args);<br>&nbsp; &nbsp; if(asm != null) {<br>&nbsp; &nbsp; &nbsp; &nbsp; return asm;<br>&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; // ... do other local look-ups<br>}

    Alternatively, some config to make the assembly write all embedded assemblies to disk (in a temp directory) on startup/request and then load from there. As this would likely enable me to locate it and dynamically load it in my child AppDomain (I believe this is usually the process for unmanaged embedded assembly loading).
  • Alex BAlex B Posts: 1,157 Diamond 4
    Hi @Izzyonstage

    The team indicated they didn't experience a problem when attempting this actually, would you be able to provide an example application replicating the issue you are experiencing?  I can reach out via a support ticket to get the file if that is possible.

    Kind regards,
    Alex
    Product Support Engineer | Redgate Software

    Have you visited our Help Center?
  • IzzyonstageIzzyonstage Posts: 5 New member
    I can put something together from the proof-of-concept app I did. I can get it to work, but only if the library dependency is merged into the main app and not embedded.
  • IzzyonstageIzzyonstage Posts: 5 New member
    If there was a way from within the assembly to inject a class that enables me to request an embedded assembly, then I could do something like:

    private static Assembly Internal_Resolve(object sender, ResolveEventArgs args) {<br>&nbsp; &nbsp; // ... initial resolver setup<br><br>&nbsp; &nbsp; // ... mainDomain is the required Assembly's AppDomain<br>&nbsp; &nbsp; // ... saResolverTypeName is the SA resolver class FullName (passed in to AppDomain Initializer)<br>&nbsp; &nbsp; // ... saResolverPath is SA resolver class location (passed in to AppDomain Initializer);<br>&nbsp; &nbsp; //&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;discovered using typeof(...).Assembly.Location<br>&nbsp; &nbsp; var parentResolver = mainDomain.CreateInstanceFromAndUnwrap(saResolverPath, saResolverTypeName);<br>&nbsp; &nbsp; parentResolver.ResourceAssembly = typeof(CallingAssemblyType).Assembly;<br>&nbsp; &nbsp; var asm = parentResolver.Resolve(sender, args);<br>&nbsp; &nbsp; if(asm != null) {<br>&nbsp; &nbsp; &nbsp; &nbsp; return asm;<br>&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; // ... do other local look-ups<br>}

    Alternatively, some config to make the assembly write all embedded assemblies to disk (in a temp directory) on startup/request and then load from there. As this would likely enable me to locate it and dynamically load it in my child AppDomain (I believe this is usually the process for unmanaged embedded assembly loading).
  • IzzyonstageIzzyonstage Posts: 5 New member
    Not sure what was going on there. Posted comment and it wouldn't let me edit it. Now there are 5 copies of it.
    I have an example PoC project I could send over. It has a working saproj which does merging of the main "library" dependency, and a broken version which is embedding that same dependency.
  • Alex BAlex B Posts: 1,157 Diamond 4
    Hi @Izzyonstage,

    I've cleared up the duplicates and I will send a message from a support ticket shortly with a link to upload the files to us for further investigation!

    Kind regards,
    Alex
    Product Support Engineer | Redgate Software

    Have you visited our Help Center?
Sign In or Register to comment.