We are testing the MAF addin to use as our addin framework. But we get stuck at a basic issue. Can we use serializable types as IContract parameters?
Both the contract and the parameter type is defined in the same assembly:
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; }
}
We are able to get everything up and running. Calling the SetCurrent results in an exception: 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]:
Loading and running of plugins:
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);
}
}
}
Plugin:
[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; }
}
You need to follow the guidelines for lifetime management. In each contract-to-view adapter you need to store a ContractHandle. This is necessary for the lifetime management of the proxies that
System.AddInimplicitly creates (remember thatSystem.AddInis based on .NET Remoting).Taken from MSDN:
If you decide to use
System.AddInin your application then you need the PipelineBuilder. In the discussion board you will find help on how to make it work with VS2010 (it is quite simple). I guess it will not be hard to make it work with VS2012 as well. This tool will take care all the System.AddIn intricacies for you. All you will need to do is create the contracts andPipelineBuilderwill create the rest of the pipeline for you. It will also make sure that you follow the guidelines on how to build your contracts which is the most important thing with System.AddIn.Before you decide on an add-in framework, don't forget to check out MEF.
MEFcan be used with Autofac and provide versioning through adapters. IMHO, the only reason that anyone should choose System.AddIn is for the isolation feature. But note that 100% isolation is only when the add-ins are loaded in a different process from the host.