2

プラグイン フレームワークを作成し、C# でリフレクションによって依存関係を読み込もうとしています。私の現在の実装は次のとおりです。

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;
    }
}

新しいアプリケーション ドメインを作成する Windows サービスがあります。次に、PluginProxy を取得し、LoadDependencies と ProcessProxy を呼び出します。依存関係を子ドメインにロードしようとしていることに注意してください。

問題は zGetTypes メソッドにあります。このメソッドは、IPlugin の種類を見つけることができます (intellisense が示しています)。ただし、Activator.CreateInstance を呼び出しても、型は初期化されません (null)。

子ドメインにいる場合、zGetTypes はタイプ IPlugin のインスタンスを作成できないことに注意してください。

アセンブリ アセンブリ = pluginDomain.Load(AssemblyName.GetAssemblyName(file.FullName));

別のアプリドメインを作成せず、アセンブリをメインのアプリドメインにロードするだけで、インスタンスの作成が機能します。私の場合、サービスの appdomain は子 appdomain を作成します。プラグインのアセンブリをプロキシにロードする責任をプッシュしたい。Proxy は MarshalByRefObject から派生するため、インスタンスを作成して Windows サービス側からアンラップできます。

その後、サービスはプラグインの読み込みとライフサイクル管理をプロキシに委任します。プロキシは、LoadDependencies へのメソッド パラメーターを介して子 appdomain のコンテキストを取得します。

IPlugin のインスタンスが作成されない理由はありますか?

4

1 に答える 1

0

プロキシ レベルでドメインを推測することで問題を解決できました。私のWindowsサービスでは、次の方法でプラグインプロキシのインスタンスを作成していました:

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

LoadAssemblies への呼び出しで、子 appdomain をパラメーターとして渡していました: LoadDependencies(string pluginDirectoryPath, AppDomain pluginDomain);

プロキシは子ドメインのコンテキスト内にあったため、これは不要でした。これで問題は解決しました。

于 2015-02-16T16:35:09.447 に答える