zoukankan      html  css  js  c++  java
  • 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接口继承。
        “业务操作窗体”只有通过暴露的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 (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, nullnew 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

    主要是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引用!

    接着是
    IPassiveAddin实现:

    WeatherPassiveAddin

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

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

     

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

     

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

     

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

        感谢关注!

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

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




  • 相关阅读:
    链表的相关算法及应用(二)
    Hexo博客同时托管到github和coding
    Valine评论出现Code 403:访问被API域名白名单拒绝,请检查你的安全域名设置
    记一次Python爬虫入门
    基于SSM的个人博客
    JSTL和EL表达式遍历List数组
    bootstrap快速开发响应式页面
    标签随机文字颜色和字体大小的实现方法
    安卓Service和Broadcast实现简单的音乐播放器
    ListView设置OnItemClickListener点击没有反应
  • 原文地址:https://www.cnblogs.com/zhuweisky/p/350786.html
Copyright © 2011-2022 走看看