在上一篇文章中,我们讲过如何从外部调用插件项目,接下来我们来看看插件项目与插件项目之间的调用。
我们来看看现在的应用场景:同样是对两个数值进行运算,MathOne是基本并且稳定的运算服务,负责对这两个数据相加并返回值。但是由于新的用户的需求发生了改变,他们希望获得的值是MathOne结果的平方数,例如:
如果我们传入的值是 (2,3),旧用户期望得到的值是 2+3 = 5 ,而新用户期望的值是 MathOne 运算结果的平方数,即是 5 2 = 25。
由于需要同时考虑新的需求并兼容旧的用户,所以我们需要加多一个插件项来为新用户响应需求。
为了让大家看起来不那么吃力,我们还是重述一下相关的接口及 MathOne 的实现:
- namespace Unit
- {
- public interface IMath
- {
- int Calculate(int value1, int value2);
- }
- }
- using System;
- using Mussel.Addins;
- namespace Unit
- {
- [MusselType("MathOne")]
- public class MathOne:AddinItem,IMath
- {
- public int Calculate(int value1, int value2)
- {
- Console.WriteLine("MathOne Calculate:");
- Console.WriteLine("\t{0} + {1} = {2}",
- value1, value2, value1 + value2);
- return value1 + value2;
- }
- }
- }
我们再来看看新的运算服务实现:
- using System;
- using Mussel.Addins;
- namespace Unit
- {
- [MusselType("MathTwo")]
- public class MathTwo:AddinItem,IMath
- {
- private string mathOneKey;
- protected string MathOneKey
- {
- get { return ReadProperty(ref mathOneKey, "MathOne"); }
- }
- public int Calculate(int value1, int value2)
- {
- Console.WriteLine("MathTwo Calculate:");
- IMath mathOne = FindAddinItem<IMath>(MathOneKey);
- int result = mathOne.Calculate(value1, value2);
- Console.WriteLine("\t{0} * {0} = {1}",
- result,result * result);
- return result * result;
- }
- }
- }
由于我们需要知道旧的运算服务 - MathOne 插件项目的具体路径,所以,我们引入了一个MathOneKey 的属性,这个属性从插件配置文件(*.addin)中对应的插件项目配置节点来读取相应的特性,用ReadProperty函数读取。ReadProperty函数其实是封装了经典的Double Lock方式,也可以看一下原码:
- protected string ReadProperty(ref string field,
- string propertyName)
- {
- return ReadProperty(ref field, propertyName, false);
- }
- protected string ReadProperty(ref string field,
- string propertyName, bool forceRead)
- {
- if (string.IsNullOrEmpty(field))
- lock (this)
- if (string.IsNullOrEmpty(field))
- {
- if (forceRead)
- field = properties.ConfigPoint.Attributes[propertyName];
- else field = Properties.ConfigPoint.GetAttribute(propertyName);
- }
- return field;
- }
再来看看如何获取到MathOne插件:IMath mathOne = FindAddinItem<IMath>(MathOneKey);
由于我们已经可以读取MathOne的完全路径,所以就可以很轻松通过上面的方式的取出MathOne。如果指定的插件项目路径有误或是插件项目不存在,上面的FindAddIntem<T>方法就会抛出NoFoundAddinItemException的异常。
接下来再看看主程序及插件配置文件的代码:
- using System;
- using Mussel;
- namespace Unit
- {
- class Program
- {
- static void Main()
- {
- MusselService service = new MusselService();
- service.Start();
- IMath mathOne =
- service.Container["/Core/Services,MathOne"] as IMath;
- if (mathOne != null) mathOne.Calculate(100, 150);
- Console.WriteLine();
- IMath mathTwo =
- service.Container["/Core/Services,MathTwo"] as IMath;
- if (mathTwo != null) mathTwo.Calculate(100, 150);
- Console.ReadLine();
- service.Dispose();
- }
- }
- }
- <?xml version="1.0" encoding="utf-8" ?>
- <Addin Name="Core">
- <ReferenceAssemblies>
- <Reference AssemblyFile="Unit.MathOne.dll"
- IsMusselAssembly="true"/>
- <Reference AssemblyFile="Unit.MathTwo.dll"
- IsMusselAssembly="true"/>
- </ReferenceAssemblies>
- <AddinNode Path="/Core/Services">
- <AddinItem ClassKey="MathOne"/>
- <AddinItem ClassKey="MathTwo"
- MathOne="/Core/Services,MathOne"/>
- </AddinNode>
- </Addin>
可以看到,主程序的代码与上篇中的基本上没有什么差异,有变动的插件配置文件。由于我们在MathTwo中需要从配置文件中读取相应节点的的附加特性(MathOne特性),所以<AddinItem ClassKey="MathTwo" MathOne="/Core/Services,MathOne"/>在这个位置多出了一个插件的自定义特性。
运行结果: