ESFramework介绍之(8)-- 客户端插件IPassiv

系统 1632 0
前文 已经提到了,在 IServerAgent 的基础上,客户端也可以采用插件的结构形式,客户端插件需要实现 IPassiveAddin 接口。
我的想法是,当客户端主程序加载一个新的 PassiveAddin 时,可以在某个菜单的子Items上添加一项,当双击这个子菜单项时,则弹出该客户端插件提供的“业务操作窗体”。这只是使用客户端插件的可行方式之一,你完全可以根据你的应用来决定使用形式。 IPassiveAddin 接口定义如下:

1 /// <summary>
2 /// IPassiveAddin用于客户端的插件。通常一个PassiveAddin对应着一个服务端的功能插件FunAddin
3 /// zhuweisky2006.03.13
4 /// </summary>
5 public interface IPassiveAddin:IAddin
6 {
7 TypeAddinFormType{ get ;} // AddinFormType必须实现IAddinForm接口
8 }
9
10 public interface IPassiveAddinForm
11 {
12 // PassiveAddin通过IServerAgent发送请求并获取结果
13 void Initialize(IServerAgentserverAgent, string userID);
14 }

IPassiveAddin 直接从 IAddin 继承,仅仅增加了一个属性 AddinFormType ,这个属性就是前面说的客户端插件提供的“业务操作窗体”。“业务操作窗体”必须从 IPassiveAddinForm 接口继承。
“业务操作窗体”只有通过暴露的 Initialize 方法获取 IServerAgent 引用后,才能发送请求获取结果。 Initialize 方法的第二个参数说明当前时哪个用户在操作,这样客户端插件在构建请求消息时,需要将 userID 填充到请求消息的消息头中去,这样服务器才会知道这个消息的来源。

下面的代码说明了客户端主程序是如何加载 IPassiveAddin 的:
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 (IAddinaddin in this .addinManagement.AddinList)
9 {
10 IPassiveAddinpassiveAddin = addin as IPassiveAddin;
11 if (passiveAddin != null )
12 {
13 ToolStripItemitem = 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,EventArgse)
21 {
22 try
23 {
24 ToolStripItemitem = (ToolStripItem)sender;
25 IPassiveAddinpassiveAddin = (IPassiveAddin)item.Tag;
26 FormaddinForm = (Form)Activator.CreateInstance(passiveAddin.AddinFormType);
27 ((IPassiveAddinForm)addinForm).Initialize( this .tcpServerAgent, this .currentUserID);
28 addinForm.Show();
29 }
30 catch (Exceptionee)
31 {
32 ee = ee;
33 }
34 }

上述的介绍没有什么难点,仔细体会一下都能明白,就不多说了。这里我给出一个测试用的功能插件和对应的客户端插件示例。 示例的功能插件用于从 http://www.webservicex.net/globalweather.asmx 通过 WebService 获取城市的天气信息,而客户端插件则用于为用户提供这项服务。

先看服务端功能插件实现:

WeatherPreAddin
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> 1 public class WeatherPreAddin:IFunAddin
2 {
3 private IContractHelpercontractHelper = 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.ServiceNamegetter实现
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.CatalogNamegetter实现
31 return "" ;
32 }
33 }
34
35 public int ServiceKey
36 {
37 get
38 {
39 // TODO:添加WeatherPreAddin.ServiceKeygetter实现
40 return 987 ;
41 }
42 }
43
44 public string Description
45 {
46 get
47 {
48 // TODO:添加WeatherPreAddin.Descriptiongetter实现
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.Enabledgetter实现
63 return true ;
64 }
65 set
66 {
67 // TODO:添加WeatherPreAddin.Enabledsetter实现
68 }
69 }
70
71 public float Version
72 {
73 get
74 {
75 // TODO:添加WeatherPreAddin.Versiongetter实现
76 return 1 ;
77 }
78 }
79
80 public string AddinType
81 {
82 get
83 {
84 // TODO:添加WeatherPreAddin.AddinTypegetter实现
85 return null ;
86 }
87 }
88
89 public AddinAppendixInfoAddinAppendixInfo
90 {
91 get
92 {
93 // TODO:添加WeatherPreAddin.AddinAppendixInfogetter实现
94 return null ;
95 }
96 }
97
98 #endregion
99
100 #region IDataDealer成员
101
102 public ESFramework.Network.NetMessageDealRequestMessage(ESFramework.Network.NetMessagereqMsg)
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 XmlParserparser = new XmlParser(result.ToString(), null );
114 WeatherPredictionContractbody = 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 (Exceptionee)
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,然后返回给客户端。

接下来看客户端插件的实现,分为两步: 首先是“业务操作窗体”界面设计
ESFramework介绍之(8)-- 客户端插件IPassiveAddin

该窗体要从IPassiveAddinForm接口继承。当点击按钮时,处理代码为:

button1_Click
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> privatevoidbutton1_Click(objectsender,System.EventArgse)
{
stringcityName=ESFramework.Common.ChsToSpellConverter.Convert(this.comboBox1.SelectedItem.ToString());
WeatherReqContractbody=newWeatherReqContract(this.contractHelper);
body.cityName=cityName;
MessageHeaderheader=newMessageHeader(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.Messagemsg=newESFramework.Network.Message(header,body);
NetMessageresMsg=this.theAgent.CommitRequest(msg,DataPriority.Common,true);
if(resMsg.Header.Result!=ServiceResultType.ServiceSucceed)
{
MessageBox.Show("没有发现对应的服务~!");
return;
}

WeatherPredictionContractresContract=newWeatherPredictionContract(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引用!


接着是
IPassiveAddin 实现:
WeatherPassiveAddin
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> 1 public class WeatherPassiveAddin:IPassiveAddin
2 {
3 public WeatherPassiveAddin()
4 {
5 }
6
7 #region IPassiveAddin成员
8
9 public TypeAddinFormType
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.ServiceNamegetter实现
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.CatalogNamegetter实现
40 return null ;
41 }
42 }
43
44 public int ServiceKey
45 {
46 get
47 {
48 // TODO:添加WeatherPassiveAddin.ServiceKeygetter实现
49 return 987 ;
50 }
51 }
52
53 public string Description
54 {
55 get
56 {
57 // TODO:添加WeatherPassiveAddin.Descriptiongetter实现
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.Enabledgetter实现
72 return true ;
73 }
74 set
75 {
76 // TODO:添加WeatherPassiveAddin.Enabledsetter实现
77 }
78 }
79
80 public float Version
81 {
82 get
83 {
84 // TODO:添加WeatherPassiveAddin.Versiongetter实现
85 return 1 ;
86 }
87 }
88
89 public string AddinType
90 {
91 get
92 {
93 // TODO:添加WeatherPassiveAddin.AddinTypegetter实现
94 return null ;
95 }
96 }
97
98 public AddinAppendixInfoAddinAppendixInfo
99 {
100 get
101 {
102 // TODO:添加WeatherPassiveAddin.AddinAppendixInfogetter实现
103 return null ;
104 }
105 }
106
107 #endregion
108 }

需要格外注意要实现AddinFormType属性,就是前面实现的“业务窗体”类型。

下图是功能服务器加载功能插件的截图:

ESFramework介绍之(8)-- 客户端插件IPassiveAddin

下图是客户端加载客户插件后的截图:

ESFramework介绍之(8)-- 客户端插件IPassiveAddin

下图是客户端插件提供服务的截图:

ESFramework介绍之(8)-- 客户端插件IPassiveAddin

经过上述的介绍,读者应该对开发服务端的功能插件和客户端插件有些了解了。快结束的时候,再为下篇blog开个头。当我们开发了客户端插件和服务端插件后,做调试是一项非常麻烦的工作,因为不仅要启动应用服务器,还要启动客户端主程序、功能服务器才行。为了简化这个过程,我实现了一个Bridge应用程序,只需要加载一pair插件(服务端插件和对应的客户插件),即可进行两个插件的调试,而不用在启动客户端、AS、FS了。

感谢关注!

上一篇: ESFramework介绍之(7)-- 服务器代理IServerAgent

转到: ESFramework 可复用的通信框架(序)




ESFramework介绍之(8)-- 客户端插件IPassiveAddin


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论