合同中可序列化类型的MAF(System.Addin)属性?

时间:2012-11-19 10:42:37

标签: c# .net maf system.addin

我们正在测试MAF插件以用作我们的插件框架。但是我们陷入了一个基本问题。我们可以使用可序列化类型作为IContract参数吗?

合同和参数类型都在同一个程序集中定义:

    public interface IHostContract : IContract
    {
        void SetCurrent(TheValue tagValue);   // does not work
        void SetCurrentSimple(double value);  // works fine
    }

    [Serializable]
    public sealed class TheValue
    {
       public int Id { get; set; }

       public double Value { get; set; }
    }

我们能够让一切运转起来。调用SetCurrent会导致异常:     AppDomainUnloadedException:

The application domain in which the thread was running has been unloaded.

Server stack trace: 
   at System.Threading.Thread.InternalCrossContextCallback(Context ctx, IntPtr ctxID, Int32 appDomainID, InternalCrossContextDelegate ftnToCall, Object[] args)
   at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoTransitionDispatch(Byte[] reqStmBuff, SmuggledMethodCallMessage smuggledMcm, SmuggledMethodReturnMessage& smuggledMrm)
   at System.Runtime.Remoting.Channels.CrossAppDomainSink.SyncProcessMessage(IMessage reqMsg)

Exception rethrown at [0]: 

加载和运行插件:

public void Run(string PluginFolder)
{
    AddInStore.Rebuild(PluginFolder);
    Collection<AddInToken> tokens = AddInStore.FindAddIns(typeof(Plugins.IPlugin), PluginFolder);

    foreach (var token in tokens)
    {
        Console.WriteLine("Found addin: " + token.Name + " v" + token.Version);
        try
        {
            var plugin = token.Activate<Plugins.IPlugin>(AddInSecurityLevel.FullTrust);
            plugin.PluginHost = this;
            plugin.Start();
            plugin.Stop();
        }
        catch (Exception exception)
        {
            Console.WriteLine("Error starting plugin: " + exception.Message);
        }
    }
}

插件:

[System.AddIn.AddIn("Plugin1", Version = "1.0.0")]
public class Plugin1 : IPlugin
{
    private int started;

    public Plugin1()
    {
        Console.WriteLine("Plugin 1 created");
    }

    public void Start()
    {
        Console.WriteLine("Plugin 1 started: {0}", started);
        started++;

        var tagValue = new TheValue { Id = 1, Value = 4.32 };
        PluginHost.SetCurrent(tagValue);
    }

    public void Stop()
    {
        Console.WriteLine("Plugin 1 stopped");
    }

    public IPluginHost PluginHost { get; set; }
}

1 个答案:

答案 0 :(得分:2)

您需要遵循lifetime management的指南。在每个合同到视图适配器中,您需要存储ContractHandle。这对System.AddIn隐式创建的代理的生命周期管理是必要的(请记住System.AddIn基于.NET Remoting。)

取自MSDN:

  

ContractHandle对终身管理至关重要。如果你没有   保持对ContractHandle对象的引用,垃圾回收会   收回它,当你的程序没有时,管道将关闭   期待它。这可能导致难以诊断的错误,   例如AppDomainUnloadedException。关机是一个正常的阶段   管道的生命,所以没有办法进行终身管理   用于检测此条件是否为错误的代码。

如果您决定在应用中使用System.AddIn,则需要PipelineBuilder。在讨论板中,您将找到有关如何使其与VS2010一起使用的帮助(这非常简单)。我想也不难让它与VS2012一起工作。此工具将为您处理所有System.AddIn复杂性。您需要做的就是创建合同,PipelineBuilder将为您创建剩余的管道。它还将确保您遵循有关如何构建合同的指导,这是System.AddIn最重要的事情。

在决定加载项框架之前,请不要忘记查看MEFMEF可与Autofac一起使用,并通过适配器提供版本控制。恕我直言,任何人都应该选择System.AddIn的唯一原因是隔离功能。但请注意,只有当加载项在与主机不同的进程中加载​​时才会出现100%isolation