--我们应当把WCF理解为一种通信技术,而不只是服务。这正是MSF的设计理念!
回到MSF,我们来看看实现请求-响应通信模式的步骤。
在上一篇文中搭建好的MSF解决方案中,我们创建了一个名字为TestService的项目,首先,添加Nuget的MSF服务端引用,
Install-PackagePDF.Net.MSF.Service现在添加一个类Service1,让它继承MSF的IService接口。具体代码如下:
usingPWMIS.EnterpriseFramework.Service.Runtime;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespaceTestService{publicclassService1:IService{publicvoidCompleteRequest(IServiceContextcontext){thrownewNotImplementedException();}publicboolIsUnSubscribe{get{thrownewNotImplementedException();}}publicboolProcessRequest(IServiceContextcontext){thrownewNotImplementedException();}}}然后,将上面方法中的异常信息注释掉,并且添加一个SayHello方法,具体修改如下:
publicclassService1:IService{publicstringSayHello(stringwho){returnstring.Format("Hello{0},IamMSFServer.",who);}publicvoidCompleteRequest(IServiceContextcontext){//thrownewNotImplementedException();}publicboolIsUnSubscribe{//get{thrownewNotImplementedException();}get{//返回True,表示当前服务不执行系统后续的服务方法的订阅处理过程,而是由用户自己输出结果数据returnfalse;}}publicboolProcessRequest(IServiceContextcontext){//thrownewNotImplementedException();returntrue;}}可以看到,实现MSF服务类,不需要先定义一个WCF服务契约接口,也没用其它WCF的代码影子,不过有点类似ASP.NET的HTTP处理过程:
我们在上一篇文中说的TestClient项目中,来编写今天的MSF客户端代码,在原有代码基础上,做适当的修改。MSF客户端调用可以分为多种方式:
本质上,MSF的客户端请求服务端的时候,是将请求的服务信息转换成MSF固有的URI地址参数信息的,类似RESTfullWebAPI的URI一样,本次请求的URI地址如下:
Service://Service1/SayHello/System.String=bluedoctor1它表示我们请求的服务类名称是Service1,请求的服务方法名称是SayHello,有一个String类型的参数并且给它赋值为bluedoctor。
client.RequestService
1,ServerResponse:【Hellobluedoctor1,IamisMSFServer.】
前面通过服务请求的URI模式虽然比较直观简洁,但使用对象来封装请求信息可能更可靠,对前面例子改写成ServiceRequest对象的代码如下:
ServiceRequestrequest=newServiceRequest();request.ServiceName="Service1";request.MethodName="SayHello";request.Parameters=newobject[]{"bluedoctor23"};client.RequestService
前面两个调用示例,其实都是传入一个委托方法给RequestService方法,然后服务端回调此委托方法的,而此委托方法的回调时机是不确定的,相对于调用线程它是异步执行的,所以我们称呼前面2种调用方式为“异步委托方法”。这种方式的一大缺点就是我们的代码中会有大量的难以阅读和调试的异步回调代码。.NET4.0之后提供了Task对象它可以简化这种调用过程,使得代码写起来就跟同步调用代码一样。这种异步调用方式,MSF也提供了支持,使用服务请求的Async后缀的方法即可:
stringserverMsg=client.RequestServiceAsync
运行上面编写的服务端和客户端,调用并不成功,在服务端出现了下面的异常:
上面截图中显示的错误信息是:“从注册的所有容器中没有找到符合当前类型的提供程序。”
这个错误信息会返回到客户端:
处理服务时错误:从注册的所有容器中没有找到符合当前类型的提供程序。这个错误提示我们没有注册我们的MSF服务类,因为MSF会通过IOC容器去寻找我们调用的服务类,所以需要注册下。MSF采用了一个简单的IOC工具,它支持通过XML配置文件类注册我们自定义的MSF服务类。
在解决方案中,看到引用了MSFHost的主项目MSFTest,nuget添加MSFHost的时候,已经添加了一个IOC配置文件:IOCConfig.xml
这个文件的使用,在MSFHost的配置文件PdfNetEF.MessageServiceHost.exe.config中做了配置:
IOCConfig.xml文件已经配置了MSF必要的内容和一些示例的测试配置,具体内容为:
在前面的示中,服务类Service1的服务方法SayHello返回的是String类型这样的简单类型,很多时候,我们需要服务方法返回结构复杂的自定义业务类型。在本次示例中,我们定义一个邮件消息类,我们新建一个C#类库项目TestDto,然后如下定义它:
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceTestDto{publicclassMailMessage{publicstringSender{get;set;}publicstringReply{get;set;}publicstringMessage{get;set;}publicDateTimeRevoveryTime{get;set;}}}然后,回到TestService项目的Service1服务类,增加一个GetMailMessage方法:
publicMailMessageGetMailMessage(stringwho){MailMessagemail=newMailMessage();mail.Reply=who;mail.Sender="MSFServer";mail.Message=string.Format("Hello{0},IamMSFServer.",who);mail.RevoveryTime=DateTime.Now;returnmail;}4.2,编写iMSF客户端代码最后,我们在TestClient中添加调用此服务的客户端代码:
client.RequestService
4,ServerResponse:【Hellobluedoctor4,IamisMSFServer.】同样,我们也可以使用ServiceRequest对象来调用这个服务:
ServiceRequestrequest2=newServiceRequest();request2.ServiceName="Service1";request2.MethodName="GetMailMessage";request2.Parameters=newobject[]{"bluedoctor567"};client.RequestService
namespaceTestClient{publicclassMailMessage2{publicstringSender{get;set;}publicstringReply{get;set;}publicstringMessage{get;set;}publicDateTimeRevoveryTime{get;set;}}}然后在客户端调用,使用这个新的在客户端定义的类型作为服务方法调用的返回值:
client.RequestService
上面的过程演示了MSF编写服务端和客户端代码的简单过程,对MSF而言,服务是本质上都是异步调用和返回的,服务方法返回结果不仅支持简单类型,还支持复杂类型;客户端支持多种调用代码书写方式。
虽然MSF是基于WCF构建的,但是从本文的示例过程看,仅使用MSF,无需掌握任何WCF的知识。
下面是完整的MSF服务端代码:
namespaceTestService{publicclassService1:IService{publicstringSayHello(stringwho){returnstring.Format("Hello{0},IamMSFServer.",who);}publicMailMessageGetMailMessage(stringwho){MailMessagemail=newMailMessage();mail.Reply=who;mail.Sender="MSFServer";mail.Message=string.Format("Hello{0},IamMSFServer.",who);mail.RevoveryTime=DateTime.Now;returnmail;}publicvoidCompleteRequest(IServiceContextcontext){//thrownewNotImplementedException();}publicboolIsUnSubscribe{//get{thrownewNotImplementedException();}get{//返回True,表示当前服务不执行系统后续的服务方法的订阅处理过程,而是由用户自己输出结果数据returnfalse;}}publicboolProcessRequest(IServiceContextcontext){//thrownewNotImplementedException();returntrue;}}}ViewCode下面是完整的客户端代码:
********PDF.NETMSF客户端测试程序*********请输入服务器的主机名或者IP地址(默认127.0.0.1):服务地址:127.0.0.1请输入服务的端口号(默认8888):服务端口号:8888当前客户端代理的服务基础地址是:net.tcp://127.0.0.1:8888MSF请求-响应模式调用示例:1,ServerResponse:【Hellobluedoctor1,IamMSFServer.】3,ServerResponse:【Hellobluedoctor23,IamMSFServer.】2,ServerResponse:【Hellobluedoctor23,IamMSFServer.】7,ServerResponse:【Hellobluedoctor567,IamMSFServer.】,RevoveryTime:2017-10-915:50:33按回车键继续4,ServerResponse:【Hellobluedoctor4,IamMSFServer.】,RevoveryTime:2017-10-915:50:335,ServerResponse:【Hellobluedoctor567,IamMSFServer.】,RevoveryTime:2017-10-915:50:336,ServerResponse:【Hellobluedoctor567,IamMSFServer.】,RevoveryTime:2017-10-915:50:33