您的位置:首页 > 其它

“一切都是消息”--MSF(消息服务框架)之【请求-响应】模式(点对点)

2017-10-09 16:04 501 查看
在前一篇, “一切都是消息”--MSF(消息服务框架)入门简介, 我们介绍了MSF基于异步通信,支持请求-响应通信模式和发布-订阅通信模式,并且介绍了如何获取MSF。今天,我们来看看如何使用MSF来做一个请求-响应通信模式的例子。

MSF封装了WCF,所以使用MSF不能像使用WCF那样直接在客户端添加服务引用,你需要手工编写客户端代理类,这样有一个好处就是代理类写的更简单,使用更灵活。我们可以看看网友写的这篇文章《不引用服务而使用WCF,手动编写客户端代理类 》,看看直接使用WCF是如何手动编写客户端代理类的。我对作者文中有一句话很认同:

--我们应当把WCF理解为一种通信技术,而不只是服务。


这正是MSF的设计理念!

回到MSF,我们来看看实现请求-响应通信模式的步骤。

一,编写MSF服务类

在上一篇文中搭建好的MSF解决方案中,我们创建了一个名字为 TestService的项目,首先,添加Nuget 的MSF服务端引用,

Install-Package PDF.Net.MSF.Service


现在添加一个类 Service1,让它继承MSF的IService 接口。具体代码如下:

using PWMIS.EnterpriseFramework.Service.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestService
{
public class Service1:IService
{
public void CompleteRequest(IServiceContext context)
{
throw new NotImplementedException();
}

public bool IsUnSubscribe
{
get { throw new NotImplementedException(); }
}

public bool ProcessRequest(IServiceContext context)
{
throw new NotImplementedException();
}
}
}


然后,将上面方法中的异常信息注释掉,并且添加一个 SayHello 方法,具体修改如下:

public class Service1:IService
{
public string SayHello(string who)
{
return string.Format("Hello {0} ,I am  MSF Server.", who);
}

public void CompleteRequest(IServiceContext context)
{
//throw new NotImplementedException();
}

public bool IsUnSubscribe
{
//get { throw new NotImplementedException(); }
get
{
//返回True ,表示当前服务不执行系统后续的服务方法的订阅处理过程,而是由用户自己输出结果数据
return false;
}
}

public bool ProcessRequest(IServiceContext context)
{
//throw new NotImplementedException();
return true;
}
}


可以看到,实现MSF服务类,不需要先定义一个WCF服务契约接口,也没用其它WCF的代码影子,不过有点类似 ASP.NET 的HTTP处理过程:

首先,每个MSF服务类都会执行 ProcessRequest 方法,它有一个IServiceContext 对象,通过它可以知道请求相关的上下文信息;

然后,会有一个 IsUnSubscribe 属性,表示本次请求是否是一个自定义的服务订阅而不再继续执行系统的服务订阅,虽然本次的示例是演示“请求-响应”的通信模式的,但是MSF本质上对此种通信模式还是通过“发布-订阅”通信模式实现的,也就是说,MSF的消息通信,始终是面向长连接的;

如果IsUnSubscribe 属性返回为False,紧接着,MSF会调用您真正的服务方法,比如这里的 SayHello 方法;

最后,你可以在 CompleteRequest 中执行一些本次服务处理的收尾工作。

二,编写MSF客户端

我们在上一篇文中说的TestClient 项目中,来编写今天的MSF客户端代码,在原有代码基础上,做适当的修改。
MSF客户端调用可以分为多种方式:

2.1,使用服务请求的URI模式:

本质上,MSF的客户端请求服务端的时候,是将请求的服务信息转换成MSF固有的URI地址参数信息的,类似RESTfull WebAPI 的URI一样,本次请求的URI地址如下:

Service://Service1/SayHello/System.String=bluedoctor1


它表示我们请求的服务类名称是 Service1,请求的服务方法名称是 SayHello,有一个String类型的参数并且给它赋值为 bluedoctor 。

MSF请求服务的时候,服务方法的参数是不用区分参数名的,只跟参数的顺序,参数的类型和参数的数量有关系,这根我们使用委托方法调用一个实际的方法一样的方式。
相关调用代码如下:

client.RequestService<string>("Service://Service1/SayHello/System.String=bluedoctor1",
PWMIS.EnterpriseFramework.Common.DataType.Text,
s =>
{
Console.WriteLine("1,Server Response:【{0}】", s);
});


如果调用服务成功,将输出结果:

1,Server Response:【Hello bluedoctor1 ,I am is MSF Server.】


2.2,使用ServiceRequest 对象来封装服务请求信息

前面通过服务请求的URI模式虽然比较直观简洁,但使用对象来封装请求信息可能更可靠,对前面例子改写成 ServiceRequest 对象的代码如下:

ServiceRequest request = new ServiceRequest();
request.ServiceName = "Service1";
request.MethodName = "SayHello";
request.Parameters = new object[] { "bluedoctor23" };
client.RequestService<string>(request,
PWMIS.EnterpriseFramework.Common.DataType.Text,
s =>
{
Console.WriteLine("2,Server Response:【{0}】", s);
});


2.3,使用异步调用方法

前面两个调用示例,其实都是传入一个委托方法给RequestService 方法,然后服务端回调此委托方法的,而此委托方法的回调时机是不确定的,相对于调用线程它是异步执行的,所以我们称呼前面2种调用方式为“异步委托方法”。这种方式的一大缺点就是我们的代码中会有大量的难以阅读和调试的异步回调代码。.NET 4.0之后提供了Task对象它可以简化这种调用过程,使得代码写起来就跟同步调用代码一样。这种异步调用方式,MSF也提供了支持,使用服务请求的Async后缀的方法即可:

string serverMsg= client.RequestServiceAsync<string>(request).Result;
Console.WriteLine("3,Server Response:【{0}】", serverMsg);


调用 RequestServiceAsync 方法返回结果的 Result方法,能够同步阻塞调用结果,使得后续代码按照我们预期的顺序执行。

三、注册MSF服务类

运行上面编写的服务端和客户端,调用并不成功,在服务端出现了下面的异常:

namespace MSFTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("******** PDF.NET MSF 客户端测试程序 *********");
Console.WriteLine();
Proxy client = new Proxy();
client.ErrorMessage += client_ErrorMessage;
Console.Write("请输入服务器的主机名或者IP地址(默认 127.0.0.1):");
string host = Console.ReadLine();
if (string.IsNullOrEmpty(host))
host = "127.0.0.1";
Console.WriteLine("服务地址:{0}",host);

Console.Write("请输入服务的端口号(默认 8888):");
string port = Console.ReadLine();
if (string.IsNullOrEmpty(port))
port = "8888";
Console.WriteLine("服务端口号:{0}", port);

client.ServiceBaseUri = string.Format("net.tcp://{0}:{1}", host, port);
Console.WriteLine("当前客户端代理的服务基础地址是:{0}",client.ServiceBaseUri);
Console.WriteLine();
Console.WriteLine("MSF 请求-响应 模式调用示例:");

client.RequestService<string>("Service://Service1/SayHello/System.String=bluedoctor1",
PWMIS.EnterpriseFramework.Common.DataType.Text,
s =>
{
Console.WriteLine("1,Server Response:【{0}】", s);
});

ServiceRequest request = new ServiceRequest();
request.ServiceName = "Service1";
request.MethodName = "SayHello";
request.Parameters = new object[] { "bluedoctor23" };
client.RequestService<string>(request,
PWMIS.EnterpriseFramework.Common.DataType.Text,
s =>
{
Console.WriteLine("2,Server Response:【{0}】", s);
});

string serverMsg= client.RequestServiceAsync<string>(request).Result;
Console.WriteLine("3,Server Response:【{0}】", serverMsg);

client.RequestService<MailMessage>("Service://Service1/GetMailMessage/System.String=bluedoctor4",
PWMIS.EnterpriseFramework.Common.DataType.Json,
mail =>
{
Console.WriteLine("4,Server Response:【{0}】,\r\n Revovery Time:{1}", mail.Message,mail.RevoveryTime);
});

ServiceRequest request2 = new ServiceRequest();
request2.ServiceName = "Service1";
request2.MethodName = "GetMailMessage";
request2.Parameters = new object[] { "bluedoctor567" };

client.RequestService<MailMessage>(request2,
PWMIS.EnterpriseFramework.Common.DataType.Json,
mail =>
{
Console.WriteLine("5,Server Response:【{0}】,\r\n Revovery Time:{1}", mail.Message, mail.RevoveryTime);
});

client.RequestService<MailMessage2>(request2,
PWMIS.EnterpriseFramework.Common.DataType.Json,
mail =>
{
Console.WriteLine("6,Server Response:【{0}】,\r\n Revovery Time:{1}", mail.Message, mail.RevoveryTime);
});

MailMessage mail2 = client.RequestServiceAsync<MailMessage>(request2).Result;
Console.WriteLine("7,Server Response:【{0}】,\r\n Revovery Time:{1}", mail2.Message, mail2.RevoveryTime);

Console.WriteLine("按回车键继续");
Console.ReadLine();

Console.WriteLine();
Console.WriteLine("MSF 发布-订阅 模式调用示例:");
string repMsg = "你好!";

client.SubscribeTextMessage("我是客户端", serverMessage => {
Console.WriteLine();
Console.WriteLine("[来自服务器的消息]::{0}", serverMessage);
});

while (repMsg != "")
{
Console.Write("回复服务器(输入为空,则退出):>>");
repMsg = Console.ReadLine();
client.SendTextMessage(repMsg);
}

Console.WriteLine("测试完成,退出");

}

static void client_ErrorMessage(object sender, MessageSubscriber.MessageEventArgs e)
{
Console.WriteLine("---处理服务时错误:{0}",e.MessageText);
}
}
}


View Code
下面是运行客户端输出的结果示例:

******** PDF.NET MSF 客户端测试程序 *********

请输入服务器的主机名或者IP地址(默认 127.0.0.1):
服务地址:127.0.0.1
请输入服务的端口号(默认 8888):
服务端口号:8888
当前客户端代理的服务基础地址是:net.tcp://127.0.0.1:8888

MSF 请求-响应 模式调用示例:
1,Server Response:【Hello bluedoctor1 ,I am  MSF Server.】
3,Server Response:【Hello bluedoctor23 ,I am  MSF Server.】
2,Server Response:【Hello bluedoctor23 ,I am  MSF Server.】
7,Server Response:【Hello bluedoctor567 ,I am  MSF Server.】,
Revovery Time:2017-10-9 15:50:33
按回车键继续
4,Server Response:【Hello bluedoctor4 ,I am  MSF Server.】,
Revovery Time:2017-10-9 15:50:33
5,Server Response:【Hello bluedoctor567 ,I am  MSF Server.】,
Revovery Time:2017-10-9 15:50:33
6,Server Response:【Hello bluedoctor567 ,I am  MSF Server.】,
Revovery Time:2017-10-9 15:50:33


在下一篇,我们将演示MSF的“发布-订阅”通信模式。

本篇测试程序全部源码,已经上传到GitHub:

https://github.com/bluedoctor/MSFTest

欢迎加入我们的QQ群讨论MSF框架的使用,群号:敏思(PWMIS) .NET 18215717,加群请注明:PDF.NET技术交流,否则可能被拒。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐