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 可复用的通信框架(序)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构