ESFramework介绍之(26)-- 支持复杂插件(InnerDealer 和 InnerDispatcher)
(本文内容适合于 ESFramework V0.2+)
通常,最单纯的情况是一个插件对应某一特定类型的功能请求,但是,在有的应用中也会出现这样的情况,有多种类型的功能请求相互关联、并且可能交叉,如果是这样,对应每种类型的请求都开发一个插件可能会非常困难,因为这可能会牵涉到插件之间的相互引用/访问,这违背了插件的“自治”性。最好的办法还是将它们放在一个插件中,通过ServiceItemIndex(你一定还记得消息头定义中除了ServiceKey外还有个ServiceItemIndex属性)来区分相互关联的各种请求类型。
当涉及的请求类型非常多时,我们的插件会变得非常复杂,通常的解决方案是在插件内部构建“内部处理器”InnerDealer,然后将ServiceItemIndex映射到对应的“内部处理器”上,这个映射可以由“内部分派器”InnerDispatcher完成。需要注意的是,并不需要为每个ServiceItemIndex都构建一个“内部处理器”,一个“内部处理器”可能能处理多个ServiceItemIndex的请求类型。下面我们重点关注“内部处理器”和“内部分派器”的实现。
内部分配器接口IInnerDispatcher定义如下:
最主要是GetDealer()方法的实现,它根据消息头中的ServiceItemIndex返回对应的内部处理器,你也许想到了,这可以通过Switch分支将serviceItemIndex映射到对应的内部处理器,然后这种集中管理的方式不是很方便,比如,当增加/删除一个内部处理器时,就要在这里增加/删除对应的分支语句。更好的办法是,让内部处理器能自己暴露它能处理的ServiceItemIndex的集合,这样,在运行时,可以通过反射动态的构建Mapping表,从而就避开了Switch语句及其引入的繁琐。
内部处理器接口定义如下,它通过ServiceIndexCollection属性暴露了它能处理的ServiceItemIndex集合。
现在,我们可以实现IInnerDispatcher的Initialize方法来动态构建Mapping表了:
可以在IAddin.OnLoading方法中调用InnerDispatcher的Initialize方法进行初始化。
IInnerDispatcher的GetDealer方法就显而易见了:
功能插件的DealRequestMessage就变得相当简单:
插件中接下来需要做的工作就是实现你需要的IInnerDealer,实现的内部处理器不需要进行注册,它会在初始化插件时动态创建并被加入到Mapping表。需要注意的是,内部处理器的实现必须有一个无参的构造函数,否则,反射创建处理器实例将会抛出异常。
上一篇文章:ESFramework介绍之(25)-- 在插件中使用NHibernate
转到 :ESFramework 可复用的通信框架(序)
通常,最单纯的情况是一个插件对应某一特定类型的功能请求,但是,在有的应用中也会出现这样的情况,有多种类型的功能请求相互关联、并且可能交叉,如果是这样,对应每种类型的请求都开发一个插件可能会非常困难,因为这可能会牵涉到插件之间的相互引用/访问,这违背了插件的“自治”性。最好的办法还是将它们放在一个插件中,通过ServiceItemIndex(你一定还记得消息头定义中除了ServiceKey外还有个ServiceItemIndex属性)来区分相互关联的各种请求类型。
当涉及的请求类型非常多时,我们的插件会变得非常复杂,通常的解决方案是在插件内部构建“内部处理器”InnerDealer,然后将ServiceItemIndex映射到对应的“内部处理器”上,这个映射可以由“内部分派器”InnerDispatcher完成。需要注意的是,并不需要为每个ServiceItemIndex都构建一个“内部处理器”,一个“内部处理器”可能能处理多个ServiceItemIndex的请求类型。下面我们重点关注“内部处理器”和“内部分派器”的实现。
内部分配器接口IInnerDispatcher定义如下:
public interface IInnerDispatcher
{
string AddinAssemblyName{set ;} //本插件程序集的名称
void Initialize() ;
IInnerDealer GetDealer(int serviceIndex) ;
}
{
string AddinAssemblyName{set ;} //本插件程序集的名称
void Initialize() ;
IInnerDealer GetDealer(int serviceIndex) ;
}
最主要是GetDealer()方法的实现,它根据消息头中的ServiceItemIndex返回对应的内部处理器,你也许想到了,这可以通过Switch分支将serviceItemIndex映射到对应的内部处理器,然后这种集中管理的方式不是很方便,比如,当增加/删除一个内部处理器时,就要在这里增加/删除对应的分支语句。更好的办法是,让内部处理器能自己暴露它能处理的ServiceItemIndex的集合,这样,在运行时,可以通过反射动态的构建Mapping表,从而就避开了Switch语句及其引入的繁琐。
内部处理器接口定义如下,它通过ServiceIndexCollection属性暴露了它能处理的ServiceItemIndex集合。
public interface IInnerDealer
{
int[] ServiceIndexCollection{get ;}
NetMessage DealRequest(NetMessage reqMsg) ;
}
{
int[] ServiceIndexCollection{get ;}
NetMessage DealRequest(NetMessage reqMsg) ;
}
现在,我们可以实现IInnerDispatcher的Initialize方法来动态构建Mapping表了:
private void Initialize()
{
Assembly[] asses = AppDomain.CurrentDomain.GetAssemblies();
Type supType = typeof(IInnerDealer) ;
foreach (Assembly ass in asses)
{
string[] names = ass.FullName.Split(',') ;
if(names[0].Trim() == this.addinAssemblyName)
{
foreach(Type t in ass.GetTypes())
{
if(supType.IsAssignableFrom(t) && (!t.IsAbstract) && (! t.IsInterface) )
{
IInnerDealer dealer = (IInnerDealer)Activator.CreateInstance(t) ;
if(dealer.ServiceIndexCollection != null)
{
foreach(int serKey in dealer.ServiceIndexCollection)
{
this.htDealer.Add(serKey ,dealer) ;
}
}
}
}
break ;
}
}
}
{
Assembly[] asses = AppDomain.CurrentDomain.GetAssemblies();
Type supType = typeof(IInnerDealer) ;
foreach (Assembly ass in asses)
{
string[] names = ass.FullName.Split(',') ;
if(names[0].Trim() == this.addinAssemblyName)
{
foreach(Type t in ass.GetTypes())
{
if(supType.IsAssignableFrom(t) && (!t.IsAbstract) && (! t.IsInterface) )
{
IInnerDealer dealer = (IInnerDealer)Activator.CreateInstance(t) ;
if(dealer.ServiceIndexCollection != null)
{
foreach(int serKey in dealer.ServiceIndexCollection)
{
this.htDealer.Add(serKey ,dealer) ;
}
}
}
}
break ;
}
}
}
可以在IAddin.OnLoading方法中调用InnerDispatcher的Initialize方法进行初始化。
IInnerDispatcher的GetDealer方法就显而易见了:
public IInnerDealer GetDealer(int serviceIndex)
{
return (IInnerDealer)this.htDealer[serviceIndex] ;
}
{
return (IInnerDealer)this.htDealer[serviceIndex] ;
}
功能插件的DealRequestMessage就变得相当简单:
public ESFramework.Network.NetMessage DealRequestMessage(ESFramework.Network.NetMessage reqMsg)
{
IInnerDealer dealer = this.dispatcher.GetDealer(reqMsg.Header.ServiceItemIndex) ;
if(dealer == null)
{
return null ;
}
return dealer.DealRequest(reqMsg) ;
}
{
IInnerDealer dealer = this.dispatcher.GetDealer(reqMsg.Header.ServiceItemIndex) ;
if(dealer == null)
{
return null ;
}
return dealer.DealRequest(reqMsg) ;
}
插件中接下来需要做的工作就是实现你需要的IInnerDealer,实现的内部处理器不需要进行注册,它会在初始化插件时动态创建并被加入到Mapping表。需要注意的是,内部处理器的实现必须有一个无参的构造函数,否则,反射创建处理器实例将会抛出异常。
上一篇文章:ESFramework介绍之(25)-- 在插件中使用NHibernate
转到 :ESFramework 可复用的通信框架(序)