2
votes

I am trying to create a plugin framework and loading dependencies by reflection in C#. My current implementation is as following:

public interface IPlugin : IDisposable
{
    void Run();
}

public interface IPluginProxy : IDisposable
{
    void RunProxy();
    void LoadDependencies(string pluginDirectoryPath, AppDomain pluginDomain);
}

public class PluginProxy : MarshalByRefObject, IPluginProxy, IDisposable
    {
        private List<IPlugin> pluginTypes = null;


        public void ProcessProxy()
        {
            //loop thorough plugin types and call Run on all plugins
            foreach(var pluginType in pluginTypes)
            {
                pluginType.Run();
            }
        }

        public void LoadDependencies(string pluginDirectoryPath, AppDomain pluginDomain)
        {
            pluginTypes = Utility.LoadAssembliesAndGetPluginTypes(pluginDirectoryPath, pluginDomain);            
        }

        //TODO:
        public void Dispose(){}

    }

public Class Utility
{
    public static List<IPlugin> LoadAssembliesAndGetPluginTypes(string pluginDirectoryPath, AppDomain pluginDomain)
    {
        try
        {
            var pluginTypes = new List<IPlugin>();
            var pluginsDirectory = new DirectoryInfo(pluginDirectoryPath);
            var files = pluginsDirectory.GetFiles("*.dll", SearchOption.TopDirectoryOnly);

            foreach (FileInfo file in files)
            {
                // Load the assembly into the child application domain.
                Assembly assembly = pluginDomain.Load(AssemblyName.GetAssemblyName(file.FullName));
                var iPluginTypes = zGetTypes(assembly);
                pluginTypes.AddRange(iPluginTypes.ToList());
            }

            return pluginTypes;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    private static IEnumerable<IPlugin> zGetTypes(Assembly assembly)
    {
        var myPlugins = from y in assembly.GetTypes()
                             where y.IsClass && y.GetInterface("IPlugin") != null &&
                                   y.GetConstructor(Type.EmptyTypes) != null
                             select Activator.CreateInstance(y) as IPlugin;
        return myPlugins;
    }
}

I have a windows service that creates a new application domain. It then get PluginProxy and calls LoadDependencies and ProcessProxy. Notice I am trying to load dependencies into child domain.

The problem is with zGetTypes method. The method is able to find IPlugin types (intellisense shows it). However, the types are not initialized (null) even if calling Activator.CreateInstance.

Please note that zGetTypes is not able to create an instance of type IPlugin if I am in the child domain.

Assembly assembly = pluginDomain.Load(AssemblyName.GetAssemblyName(file.FullName));

If I don't create separate appdomain and just load the assembly into main appdomain, creating of the instance works. In my case Service's appdomain creates child appdomain. I want to push the responsibility of loading assemblies of plugin to proxy. Proxy derives from MarshalByRefObject so I can create an instance and unwrap it from windows service side.

The service then delegate the loading and lifecycle management of plugins to proxy. The proxy would get the context of child appdomain through the method parameter to LoadDependencies.

Any ideas why would instance(s) of IPlugin be not created?

1

1 Answers

0
votes

I was able to resolve the issue by inferring domain at the proxy level. In my windows service, i was creating instance of plugin proxy following way:

IPluginProxy pluginProxy = IPluginProxy)
(pluginDomain
.CreateInstanceFromAndUnwrap(directory.FullName + "\\Utility.Common.dll", 
typeof(PluginProxy).FullName));

In my call to LoadAssemblies, I was passing the child appdomain as parameter: LoadDependencies(string pluginDirectoryPath, AppDomain pluginDomain);

This was unnecessary since proxy was within the context of child domain. This solved the issue.