我们正在测试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; }
}
答案 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最重要的事情。
在决定加载项框架之前,请不要忘记查看MEF。 MEF
可与Autofac一起使用,并通过适配器提供版本控制。恕我直言,任何人都应该选择System.AddIn的唯一原因是隔离功能。但请注意,只有当加载项在与主机不同的进程中加载时才会出现100%isolation。