1
votes

I have program with all DLLs hidden inside of one executable file. I am developing plugin support for this program.

All DLL in exe are stored in as Embedded Resources. Following code is used to access these embeded resources:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    var resourceName = Assembly.GetExecutingAssembly()
                        .GetManifestResourceNames()
                        .FirstOrDefault(x => x.EndsWith(new AssemblyName(args.Name).Name + ".dll"));

    using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
    {
        if (stream == null)
            return null; 

        var assemblyData = new byte[stream.Length];
        stream.Read(assemblyData, 0, assemblyData.Length);
        return Assembly.Load(assemblyData);
    }
};

Plugins are loaded in separate domain for possibility to unload them:

public static T CreateInstanceInNewAppDomain<T>(bool shadowCopy = true)
{
    var cdSetupInf = AppDomain.CurrentDomain.SetupInformation;
    var separateDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null,
                                            new AppDomainSetup()
                                            {
                                                LoaderOptimization = LoaderOptimization.MultiDomain,
                                                ApplicationBase = cdSetupInf.ApplicationBase,
                                                PrivateBinPath = cdSetupInf.PrivateBinPath,
                                                ShadowCopyFiles = shadowCopy ? "true" : "false"
                                            }); 

    var type = typeof(T);
    return (T)separateDomain.CreateInstanceFromAndUnwrap(type.Assembly.Location, type.FullName);
}

The most important part of previous code is call „CreateInstanceFromAndUnwrap“ for creation object on separate domain. This part of code would work well if DLL containing type would be on HDD. Since it is loaded from Embedded Resources the assemblyFile parameter (represented as type.Assembly.Location) is empty. Therefore I am not able to create instance of my IPluginAccessor which I am using for accessing functionality in plugins. Is there any way how can create instance of type in separate domain without need to specify assemblyName? It would be great if there would be something like AppDomain.CreateInstanceFromAndUnwrap(Type type). If I looked well, there is only Activator.CreateInstance(Type type) but this works for current domain and not one I specify.

Thanks a lot

1
I'm afraid it is not possible and the simplest workaround would be to generate temporary dll within some temp directory and load assembly from this location.Konrad Kokosa
This is the way I would like to avoid. Because I hope I can :-)user2126375

1 Answers

0
votes

I think you can use Callback which will be executed in the new AppDomain.

Define an helper class:

class AnotherAppDomainPluginBuilder<T> : MarshalByRefObject
    where T : new()
{
    T Result { get; set; }

    public void Create()
    {
        LoadRelevantDlls();
        this.Result = new T();
    }

    void LoadRelevantDlls()
    {
        // load whatever DLLs in whatever way you would like to
    }
}

Then instead of:

return (T)separateDomain.CreateInstanceFromAndUnwrap(type.Assembly.Location, type.FullName);

Write:

AnotherAppDomainPluginBuilder<T> builder =
    (T)separateDomain.CreateInstanceFromAndUnwrap(
        Assembly.CurrentAssembly,
        typeof(AnotherAppDomainPluginBuilder<T> ));

separateDomain.DoCallback(builder.Create);

return builder.Result;