日积(Running)月累(ZSSURE):WCF学习之“通过事件绑定控制WinForm宿主程序主界面控件”

来源:互联网 发布:鼎信网络充话费不到账 编辑:程序博客网 时间:2024/06/06 01:25

背景:

WCF服务需要寄宿到相应的可运行进程中执行,常见的有四种寄宿,分别是控制台程序、WinForm程序、IIS和Windows服务。之前学习老A博客和《WCF全面解析》时最常用到的是控制台寄宿,近期由于项目需求,需要在WinForm程序中调用WCF服务,本博文通过一个简单的实例来演示WCF在WinForm中的寄宿。并着重介绍如何利用事件绑定控制宿主主UI界面控件。

题记:

之前一直坚守在C++阵地,对于新语言、新技术(诸如Python、J2EE、Bigdata、AI)不甚感冒。自以为“原理”都是想通的,无非就是语法略有不同、集成的API数量级不同而已,想以不变应万变。——归根结底,这是一种精神上的懒惰与懦弱,尤其当从Student Context切换到Working Context后,倍感担忧。大脑能分配给每个任务的时间片越来越短,却无法切换到多CPU/多核模式,加之‘年老体衰’,‘内存’脑容量越来越少,汗Σ( ° △ °|||)︴啊。
穷途末路,遂求变革。开始写写技术博客,将已有知识转存到其他介质以弥补内存日渐不足;浏览学习新技术,提升新技能,弥补这台老CPU效率。
书归正传,之前很少用C/C++开发网络式、分布式应用,大多停留在C/S层面。因此在互联网+时代早已落伍,遂借着工作和兴趣,开始涉猎WCF和J2EE,顿时觉得好高大上,兴趣盎然,不过WCF(或J2EE)都是之前技术体系的集大成者,学习曲线及其陡峭,啃了半个月的书本却总感觉闷闷的,不敞亮,还需加把劲,再接再厉。
下面就简单记录一下初次学习WCF的体会,文中会给出一个WCF实例,实例模拟的应用场景是:

两个WinForm终端A和B,A中寄宿一项WCF服务,B中调用该服务向A发送指令消息,并在A的界面中显示(其实类似于QQ聊天)

结构示意图如下:
这里写图片描述

WCF简介:

微软从.NET3.0开始引入了WPF、WCF和WF三模块。
这里写图片描述

WPF,Windows Presentation Foundation是微软用于Windows的同一显示子系统,由显示引擎和托管代码框架组成。Windows Presentation Foundation 统一了 Windows 创建、显示和操作文档、媒体和用户界面 (UI) 的方式,使开发人员和设计人员可以创建更好的视觉效果、不同的用户体验。
WCF,Windows Communication Foundation 是微软为构建面向服务的应用提供的分布式通信编程框架。使用该框架,开发人员可以构建跨平台、安全、可靠和支持事务处理的企业级互联应用解决方案。
WF,Windows Workflow Foundation是一个通用的编程框架,它可用于创建需要对外部实体的信号作出响应的交互式程序。交互式程序的基本特征是它会在执行期间暂停某一长短未知的时段,以等待输入。

本博文主要用到的是上述三种新特性中的WCF,即分布式通信框架。Windows Communication Foundation,WCF,是微软开发的构建面向服务应用的统一编程模型,一种框架。WCF是一个运行时环境和一套API,用于创建在服务与客户端间传递消息的新系统。
WCF是基于消息的,任何东西都可以被当做是消息在编程模型中统一处理。消息在终结点间传递。终结点(Endpoints)是消息发送或消息接收(或者发送与接收)的地方。利用WCF,可以将数据以异步消息的方式从一个服务终结点发送到另一个。消息可以是多种多样,简到XML格式的一个字符或一个单词,繁至二进制数据流。

由于刚刚涉猎,博文中就不过多介绍WCF的细节了,自己也没搞懂吃透。有兴趣可以浏览WCF大神的博客专栏 。从一个初学者不成熟的角度来看,

【拙见1】:WCF是一种框架,最简单的情境中只要你在两端(服务端和客户端)做好约定(契约),通过WCF绑定就可以让两端进行相互调用,无论两者是否在同一进程、是否在同一主机、是否在同一平台,WCF技术使得跨进程、跨平台可以悄无声息。

【拙见2】:姑且这么认为,WCF大大减少了程序员在底层交互上的工作,只需要关注业务层的逻辑即可。大大减少了程序部署的难度,使得应用普适性更强。

WCF寄宿:

直接以实例来讲解吧,操纵系统运行和分配资源的最小单位是进程。然而在WCF开发过程中,往往会将Contract(契约,或者说是约定)、Service(契约具体实现)分别以库的形式发布,因此在实际应用中要想使用WCF服务,需要将对应WCF库寄宿到可执行环境中,常见的有四种方式——控制台程序、Winform程序、IIS和Windows Service。这里按照博文之前的使用场景,使用Winform程序寄宿WCF服务,并给出具体的实例,其他方式的介绍可参考老A的博客

WinFrom4HostWCFService:

WCF契约:

从编程角度来看,契约(Contracts)就是WCF框架中用于制定服务的统一标准,就是一些接口。
【注】:这种说法不够精确,严格的说ServiceContract是一堆接口;而在接口的相关约束、配置中需要其他契约的配合,诸如接口中具体函数需要使用OperationContract、函数的具体参数需要DataContract、函数体内的异常和错误需要FaultContract,除此以外还有具体交互过程中使用的MessageContract。

为了简单起见,姑且认为契约就是用于约束接口的相关规定吧。本文为了简单起见,设想服务端提供的服务是“收到Winform客户端发送的消息,直接在服务端主窗口中利用MessageBox以消息窗口形式显示出来。这里需要注意的是此处建立的WCF契约类是传统的C#类库,在该类库中如何才能在接收到客户端发送的请求后,主动触发主UI界面进行弹窗消息提示呢?这里就要涉及到C#的规定,对于Winform工程只有创建控件的主UI线程才能对其操作。那我们该如何实现呢?搜索了部分资料后发现,在WCF的契约服务类中可以使用通常的事件绑定。具体代码如下:
【–服务契约类–】

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;namespace WCF.WcfContract{[ServiceContract(Name="WcfNotify")]public interface INotify2WinForm{[OperationContract]void Notify2WinForm(string message);}}


【–服务契约实现类–】

using System;using System.Collections.Generic;using System.Linq;using System.Text;using WCF.WcfContract;using System.ServiceModel;namespace WCF.WcfService{public delegate void DisplayMessage(string mes);[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]public class NotifyService:INotify2WinForm{public DisplayMessage displayMessage;public void Notify2WinForm(string message){if (!string.IsNullOrWhiteSpace(message)){if (null != displayMessage)displayMessage(message);}}}}


【注1】:在建立Contract和Service具体实现类时需要在工程中添加System.ServiceModel引用
【注2】: ServiceContract必须添加InstanceContextMode=InstanceContextMode.Single设置,否则无法正常启动WCF服务

WCF寄宿:

寄宿就是建立一种可执行环境,然后调用WCF服务类库,即DLL动态库。这里我们建立的是Windows窗体应用程序,即Winform程序。程序界面中只有两个按钮,用于启动和关闭WCF服务。界面如下所示:
这里写图片描述
这里采用代码方式来实现WCF服务,具体的实现代码如下所示:

NotifyService wcfService = new NotifyService();wcfService.displayMessage = this.DisplayMessage;host = new ServiceHost(wcfService);WSHttpBinding httpBinding = new WSHttpBinding(SecurityMode.None);host.AddServiceEndpoint(typeof(INotify2WinForm), httpBinding, "http://localhost:8900");NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.None);host.AddServiceEndpoint(typeof(INotify2WinForm), tcpBinding, "net.tcp://localhost:1700/");host.Open();


WCF客户端:

为了演示方便,并未使用SvcUtil.exe来添加WCF服务,直接在客户端工程中添加服务契约工程的引用。然后在主程序中直接使用Coding的方式创建信道调用WCF服务,具体代码如下:

EndpointAddress edpHttp = new EndpointAddress("http://localhost:8900/");EndpointAddress edpTcp = new EndpointAddress("net.tcp://localhost:1700/");WSHttpBinding httpBinding = new WSHttpBinding(SecurityMode.None);ChannelFactory<INotify2WinForm> factory = new ChannelFactory<INotify2WinForm>(httpBinding);INotify2WinForm channel = factory.CreateChannel(edpHttp);channel.Notify2WinForm("WinForm4WCFTest-zssure");((IClientChannel)channel).Close();

总结:

实际测试结果如下,先启动WCF宿主程序WinForm4HostWCF,单击“启动WCF”按钮后;启动客户端WinformClient4WcfTest。在窗口中输入任意字符串,例如zssure test WCF 2015/04/04,单击“testWCF”按钮后,会看到WinForm4HostWCF界面弹出消息窗口,显示zssure test WCF 2015/04/04。具体结果图如下:
这里写图片描述

【ZSSURE】:

此次演示过程中会发生众多其他错误,比如在WinForm4HostWCF窗口的MessageBox未关闭的情况下,客户端再次单击“testWCF”时服务端无法响应,且界面会卡死如果长时间未关闭MessageBox窗口,会弹出超时响应的错误窗口。这说明WCF框架其底层的机制很繁琐,虽然上手容易但是要想开发出稳定的、适于具体场景的应用需要具有丰富的实战经验,再接再厉还需继续努力,有时间会对上述两个错误进行详细分析。敬请期待……

【源码下载】:

【GitHub】: 源代码下载 【注】:近期Github受到攻击,上传可能会有延时,请耐心等待……
【CSDN】: 源代码下载




作者:zssure@163.com
时间:2015-04-04

0 0