ESFramework介绍之(8)-- 客户端插件IPassiveAddin
??? 前文已经提到了,在IServerAgent的基础上,客户端也可以采用插件的结构形式,客户端插件需要实现IPassiveAddin接口。
????我的想法是,当客户端主程序加载一个新的PassiveAddin时,可以在某个菜单的子Items上添加一项,当双击这个子菜单项时,则弹出该客户端插件提供的“业务操作窗体”。这只是使用客户端插件的可行方式之一,你完全可以根据你的应用来决定使用形式。IPassiveAddin接口定义如下:
?1????
///
?
<summary>
?2? ???? /// ?IPassiveAddin?用于客户端的插件。通常一个PassiveAddin对应着一个服务端的功能插件FunAddin ?3? ???? /// ?zhuweisky?2006.03.13 ?4? ???? /// ? </summary> ?5? ???? public ? interface ?IPassiveAddin?:?IAddin ?6? ????{ ?7? ????????Type?AddinFormType{ get ?;}? // AddinFormType必须实现IAddinForm接口 ?8? ????} ?9? 10? ???? public ? interface ?IPassiveAddinForm 11? ????{ 12? ???????? // PassiveAddin通过IServerAgent发送请求并获取结果 13? ???????? void ?Initialize(IServerAgent?serverAgent?, string ?userID)?; 14? ????} ??? IPassiveAddin直接从IAddin继承,仅仅增加了一个属性AddinFormType,这个属性就是前面说的客户端插件提供的“业务操作窗体”。“业务操作窗体”必须从IPassiveAddinForm接口继承。
?1?
?????????
private
?
void
?LoadPassiveAddins() ?2? ????????{ ?3? ???????????? this .lIToolStripMenuItem_addin.DropDownItems.Clear(); ?4? ?5? ???????????? string ?directory? = ?System.IO.Directory.GetParent(System.Windows.Forms.Application.ExecutablePath).FullName; ?6? ???????????? this .addinManagement.LoadAllAddins(directory,? true ); ?7? ?8? ???????????? foreach ?(IAddin?addin? in ? this .addinManagement.AddinList) ?9? ????????????{ 10? ????????????????IPassiveAddin?passiveAddin? = ?addin? as ?IPassiveAddin; 11? ???????????????? if ?(passiveAddin? != ? null ) 12? ????????????????{ 13? ????????????????????ToolStripItem?item? = ? new ?ToolStripMenuItem(passiveAddin.ServiceName,? null ,? new ?EventHandler( this .OnAddinMenuClicked)); 14? ????????????????????item.Tag? = ?passiveAddin; 15? ???????????????????? this .lIToolStripMenuItem_addin.DropDownItems.Add(item); 16? ????????????????} 17? ????????????} 18? ????????} 19? 20? ???????? private ? void ?OnAddinMenuClicked( object ?sender,?EventArgs?e) 21? ????????{ 22? ???????????? try 23? ????????????{ 24? ????????????????ToolStripItem?item? = ?(ToolStripItem)sender; 25? ????????????????IPassiveAddin?passiveAddin? = ?(IPassiveAddin)item.Tag; 26? ????????????????Form?addinForm? = ?(Form)Activator.CreateInstance(passiveAddin.AddinFormType); 27? ????????????????((IPassiveAddinForm)addinForm).Initialize( this .tcpServerAgent?, this .currentUserID); 28? ????????????????addinForm.Show(); 29? ????????????} 30? ???????????? catch ?(Exception?ee) 31? ????????????{ 32? ????????????????ee? = ?ee; 33? ????????????} 34? ????????} ??? 上述的介绍没有什么难点,仔细体会一下都能明白,就不多说了。这里我给出一个测试用的功能插件和对应的客户端插件示例。示例的功能插件用于从http://www.webservicex.net/globalweather.asmx 通过WebService获取城市的天气信息,而客户端插件则用于为用户提供这项服务。 先看服务端功能插件实现:
WeatherPreAddin
??1?public?class?WeatherPreAddin?:IFunAddin ??2?????{ ??3?????????private?IContractHelper?contractHelper?=?new?ContractHelper()?; ??4? ??5?????????public?WeatherPreAddin() ??6?????????{ ??7????????????? ??8?????????} ??9? ?10?????????#region?IAddin?成员 ?11? ?12?????????public?string?ServiceName ?13?????????{ ?14?????????????get ?15?????????????{ ?16?????????????????//?TODO:??添加?WeatherPreAddin.ServiceName?getter?实现 ?17?????????????????return?"天气预测服务"; ?18?????????????} ?19?????????} ?20? ?21?????????public?void?OnLoading() ?22?????????{ ?23?????????????//?TODO:??添加?WeatherPreAddin.OnLoading?实现 ?24?????????} ?25? ?26?????????public?string?CatalogName ?27?????????{ ?28?????????????get ?29?????????????{ ?30?????????????????//?TODO:??添加?WeatherPreAddin.CatalogName?getter?实现 ?31?????????????????return?""; ?32?????????????} ?33?????????} ?34? ?35?????????public?int?ServiceKey ?36?????????{ ?37?????????????get ?38?????????????{ ?39?????????????????//?TODO:??添加?WeatherPreAddin.ServiceKey?getter?实现 ?40?????????????????return?987?; ?41?????????????} ?42?????????} ?43? ?44?????????public?string?Description ?45?????????{ ?46?????????????get ?47?????????????{ ?48?????????????????//?TODO:??添加?WeatherPreAddin.Description?getter?实现 ?49?????????????????return?""; ?50?????????????} ?51?????????} ?52? ?53?????????public?void?BeforeTerminating() ?54?????????{ ?55?????????????//?TODO:??添加?WeatherPreAddin.BeforeTerminating?实现 ?56?????????} ?57? ?58?????????public?bool?Enabled ?59?????????{ ?60?????????????get ?61?????????????{ ?62?????????????????//?TODO:??添加?WeatherPreAddin.Enabled?getter?实现 ?63?????????????????return?true; ?64?????????????} ?65?????????????set ?66?????????????{ ?67?????????????????//?TODO:??添加?WeatherPreAddin.Enabled?setter?实现 ?68?????????????} ?69?????????} ?70? ?71?????????public?float?Version ?72?????????{ ?73?????????????get ?74?????????????{ ?75?????????????????//?TODO:??添加?WeatherPreAddin.Version?getter?实现 ?76?????????????????return?1; ?77?????????????} ?78?????????} ?79? ?80?????????public?string?AddinType ?81?????????{ ?82?????????????get ?83?????????????{ ?84?????????????????//?TODO:??添加?WeatherPreAddin.AddinType?getter?实现 ?85?????????????????return?null; ?86?????????????} ?87?????????} ?88? ?89?????????public?AddinAppendixInfo?AddinAppendixInfo ?90?????????{ ?91?????????????get ?92?????????????{ ?93?????????????????//?TODO:??添加?WeatherPreAddin.AddinAppendixInfo?getter?实现 ?94?????????????????return?null; ?95?????????????} ?96?????????} ?97? ?98?????????#endregion ?99? 100?????????#region?IDataDealer?成员 101? 102?????????public?ESFramework.Network.NetMessage?DealRequestMessage(ESFramework.Network.NetMessage?reqMsg) 103?????????{???? 104????????????? 105?????????????try 106?????????????{ 107?????????????????string?url?=?"http://www.webservicex.net/globalweather.asmx"?; 108?????????????????string[]?args?=?new?string[2]?; 109?????????????????args[0]?=?this.contractHelper.GetStrFromStream(reqMsg.Body?,reqMsg.BodyOffset?,reqMsg.Header.MessageBodyLength)?; 110?????????????????args[1]?=?"China"?; 111?????????????????object?result?=?WebServiceHelper.InvokeWebService(url?,"GetWeather"?,args)?; 112????????????? 113?????????????????XmlParser?parser?=?new?XmlParser(result.ToString()?,null)?; 114?????????????????WeatherPredictionContract?body?=?new?WeatherPredictionContract(this.contractHelper)?; 115?????????????????body.Pressure?=?parser.GetSingleLayerConfigValue("Pressure")?; 116?????????????????body.PressureLen?=?this.contractHelper.GetBytesFromStr(body.Pressure).Length?; 117? 118?????????????????body.PreTime??=?parser.GetSingleLayerConfigValue("Time")?; 119?????????????????body.PreTimeLen?=?this.contractHelper.GetBytesFromStr(body.PreTime).Length?; 120? 121?????????????????body.Temprature?=?parser.GetSingleLayerConfigValue("Temperature")?; 122?????????????????body.TempratureLen?=?this.contractHelper.GetBytesFromStr(body.Temprature).Length?; 123? 124?????????????????body.Visbility??=?parser.GetSingleLayerConfigValue("Visibility")?; 125?????????????????body.VisbilityLen?=?this.contractHelper.GetBytesFromStr(body.Visbility).Length?; 126? 127?????????????????body.Wind??=?parser.GetSingleLayerConfigValue("Wind")?; 128?????????????????body.WindLen?=?this.contractHelper.GetBytesFromStr(body.Wind).Length?; 129? 130?????????????????reqMsg.Header.MessageBodyLength?=?body.GetStreamLength()?; 131? 132?????????????????return?new?NetMessage(reqMsg.Header?,body.ToStream()?,0)?; 133? 134?????????????} 135?????????????catch(Exception?ee) 136?????????????{ 137?????????????????ee?=?ee?; 138?????????????????reqMsg.Header.MessageBodyLength?=?0?; 139?????????????????reqMsg.Header.Result?=?ServiceResultType.FailureByOtherCause?; 140?????????????????return?new?NetMessage(reqMsg.Header?,null); 141?????????????} 142?????????} 143? 144?????????#endregion 145?????} 主要是DealRequestMessage方法的实现,代码非常简单,通过WebService获取指定城市的天气情况,将返回的XML解析封装成IContract,然后返回给客户端。 接下来看客户端插件的实现,分为两步:首先是“业务操作窗体”界面设计。 ?该窗体要从IPassiveAddinForm接口继承。当点击按钮时,处理代码为:
button1_Click
??????? private?void?button1_Click(object?sender,?System.EventArgs?e) ????????{ ????????????string?cityName?=?ESFramework.Common.ChsToSpellConverter.Convert(this.comboBox1.SelectedItem.ToString())?; ????????????WeatherReqContract?body?=?new?WeatherReqContract(this.contractHelper)?; ????????????body.cityName?=?cityName?; ????????????MessageHeader?header?=?new?MessageHeader(this.contractHelper)?; ????????????header.TypeKey?=?int.Parse(this.textBox_asCityCode.Text.Trim())?; ????????????header.ServiceKey?=?987?; ????????????header.UserID?????=?this.curUserID?; ????????????header.UserIDLen??=?this.contractHelper.GetBytesFromStr(this.curUserID).Length?; ????????????header.MessageBodyLength?=?body.GetStreamLength()?; ????????????ESFramework.Network.Message?msg?=?new?ESFramework.Network.Message(header?,body)?; ???????????? NetMessage?resMsg?=?this.theAgent.CommitRequest(msg?,DataPriority.Common?,true)?; ????????????if(resMsg.Header.Result?!=?ServiceResultType.ServiceSucceed) ????????????{ ????????????????MessageBox.Show("没有发现对应的服务~!")?; ????????????????return?; ????????????} ????????????WeatherPredictionContract?resContract?=?new?WeatherPredictionContract(this.contractHelper)?; ????????????resContract.FillMyself(resMsg.Body?,resMsg.BodyOffset)?; ????????????this.groupBox1.Text?=?"服务结果--"?+?this.comboBox1.SelectedItem.ToString()?; ????????????this.label_pressure.Text?=?resContract.Pressure?; ????????????this.label_temp.Text?????=?resContract.Temprature?; ????????????this.label_vis.Text??????=?resContract.Visbility?; ????????????this.label_wind.Text?????=?resContract.Wind?; ????????????this.label_time.Text?????=?resContract.PreTime?; ????????} ??? 注意,theAgent成员即是通过Initialize传入的IServerAgent引用!
WeatherPassiveAddin
??1???? public?class?WeatherPassiveAddin?:IPassiveAddin ??2?????{ ??3?????????public?WeatherPassiveAddin() ??4?????????{ ??5?????????} ??6? ??7?????????#region?IPassiveAddin?成员 ??8? ??9?????????public?Type?AddinFormType ?10?????????{ ?11?????????????get ?12?????????????{???????????????? ?13?????????????????return?typeof(AddinForm);?//AddinForm即前面实现的业务窗体 ?14?????????????} ?15?????????} ?16? ?17?????????#endregion ?18? ?19?????????#region?IAddin?成员 ?20? ?21?????????public?string?ServiceName ?22?????????{ ?23?????????????get ?24?????????????{ ?25?????????????????//?TODO:??添加?WeatherPassiveAddin.ServiceName?getter?实现 ?26?????????????????return?"天气预测服务"; ?27?????????????} ?28?????????} ?29? ?30?????????public?void?OnLoading() ?31?????????{ ?32?????????????//?TODO:??添加?WeatherPassiveAddin.OnLoading?实现 ?33?????????} ?34? ?35?????????public?string?CatalogName ?36?????????{ ?37?????????????get ?38?????????????{ ?39?????????????????//?TODO:??添加?WeatherPassiveAddin.CatalogName?getter?实现 ?40?????????????????return?null; ?41?????????????} ?42?????????} ?43? ?44?????????public?int?ServiceKey ?45?????????{ ?46?????????????get ?47?????????????{ ?48?????????????????//?TODO:??添加?WeatherPassiveAddin.ServiceKey?getter?实现 ?49?????????????????return?987; ?50?????????????} ?51?????????} ?52? ?53?????????public?string?Description ?54?????????{ ?55?????????????get ?56?????????????{ ?57?????????????????//?TODO:??添加?WeatherPassiveAddin.Description?getter?实现 ?58?????????????????return?null; ?59?????????????} ?60?????????} ?61? ?62?????????public?void?BeforeTerminating() ?63?????????{ ?64?????????????//?TODO:??添加?WeatherPassiveAddin.BeforeTerminating?实现 ?65?????????} ?66? ?67?????????public?bool?Enabled ?68?????????{ ?69?????????????get ?70?????????????{ ?71?????????????????//?TODO:??添加?WeatherPassiveAddin.Enabled?getter?实现 ?72?????????????????return?true; ?73?????????????} ?74?????????????set ?75?????????????{ ?76?????????????????//?TODO:??添加?WeatherPassiveAddin.Enabled?setter?实现 ?77?????????????} ?78?????????} ?79? ?80?????????public?float?Version ?81?????????{ ?82?????????????get ?83?????????????{ ?84?????????????????//?TODO:??添加?WeatherPassiveAddin.Version?getter?实现 ?85?????????????????return?1; ?86?????????????} ?87?????????} ?88? ?89?????????public?string?AddinType ?90?????????{ ?91?????????????get ?92?????????????{ ?93?????????????????//?TODO:??添加?WeatherPassiveAddin.AddinType?getter?实现 ?94?????????????????return?null; ?95?????????????} ?96?????????} ?97? ?98?????????public?AddinAppendixInfo?AddinAppendixInfo ?99?????????{ 100?????????????get 101?????????????{ 102?????????????????//?TODO:??添加?WeatherPassiveAddin.AddinAppendixInfo?getter?实现 103?????????????????return?null; 104?????????????} 105?????????} 106? 107?????????#endregion 108?????} ??? 需要格外注意要实现AddinFormType属性,就是前面实现的“业务窗体”类型。? 下图是功能服务器加载功能插件的截图: ? 下图是客户端加载客户插件后的截图: ? 下图是客户端插件提供服务的截图: ? ???? 经过上述的介绍,读者应该对开发服务端的功能插件和客户端插件有些了解了。快结束的时候,再为下篇blog开个头。当我们开发了客户端插件和服务端插件后,做调试是一项非常麻烦的工作,因为不仅要启动应用服务器,还要启动客户端主程序、功能服务器才行。为了简化这个过程,我实现了一个Bridge应用程序,只需要加载一pair插件(服务端插件和对应的客户插件),即可进行两个插件的调试,而不用在启动客户端、AS、FS了。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |