昨天发布了《WCF服务创建与使用(请求应答模式)》,今天继续学习与强化在双工模式下WCF服务创建与使用,步骤与代码如下。
第一步,定义服务契约(Service Contract),注意ServiceContract特性上需指定回调契约
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
//服务契约
using
System.ServiceModel;
namespace
WcfServiceLibrary1
{
[ServiceContract(Namespace =
"http://www.zuowenjun.cn"
,
CallbackContract =
typeof
(ICallback))]
public
interface
IHello
{
[OperationContract(IsOneWay =
true
)]
void
SetName(
string
name);
}
}
//回调契约(由于回调契约本质也是一个服务契约,所以定义方式和一般意义上的服务契约基本一样。
//有一点不同的是,由于定义服务契约时候已经通过[ServiceContract(CallbackContract=typeof(ICallback))]指明ICallback是一个服务契约了,所以ICallback不再需要添加ServiceContractAttribute特性)
using
System.ServiceModel;
namespace
WcfServiceLibrary1
{
public
interface
ICallback
{
[OperationContract(IsOneWay =
true
)]
void
ShowHello(
string
name);
}
}
|
第二步,实现服务契约,这里通过OperationContext.Current.GetCallbackChannel()获取回调契约
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
using
System.ServiceModel;
namespace
WcfServiceLibrary1
{
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public
class
HelloService:IHello
{
public
void
SetName(
string
name)
{
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
callback.ShowHello(name);
}
}
}
|
注意:ConcurrencyMode = ConcurrencyMode.Reentrant是设置并发模式,Reentrant与Multiple均可适用于多并发,默认是Single
第三步,创建服务寄宿程序,方法很多,我这里采取常用的配置方法
1.CONFIG文件配置部份:
(注: 1.在WCF预定义绑定类型中,WSDualHttpBinding和NetTcpBinding均提供了对双工通信的支持,但是两者在对双工通信的实现机制上却有本质的区别。WSDualHttpBinding是基于HTTP传输协议的;而HTTP协议本身是基于请求-回复的传输协议,基于HTTP的通道本质上都是单向的。WSDualHttpBinding实际上创建了两个通道,一个用于客户端向服务端的通信,而另一个则用于服务端到客户端的通信,从而间接地提供了双工通信的实现。而NetTcpBinding完全基于支持双工通信的TCP协议。
2.若绑定类型采用NetTcpBinding,则地址应变更为:net.tcp://127.0.0.1:10800/HelloService,且不能有behaviorConfiguration配置)
1
2
3
4
5
6
7
8
9
10
11
|
<?
xml
version="1.0" encoding="utf-8" ?>
<
configuration
>
<
system.serviceModel
>
<
services
>
</
service
>
<
service
name="WcfServiceLibrary1.HelloService">
<
endpoint
address="http://127.0.0.1:10800/HelloService" binding="wsDualHttpBinding" contract="WcfServiceLibrary1.IHello"></
endpoint
>
</
service
>
</
services
>
</
system.serviceModel
>
</
configuration
>
|
2.代码部份:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
using
System;
using
WcfServiceLibrary1;
using
System.ServiceModel;
using
System.ServiceModel.Description;
namespace
ConsoleApplicationHost
{
class
Program
{
static
void
Main(
string
[] args)
{
BuildHelloServiceHostByConfig();
}
static
void
BuildHelloServiceHostByConfig()
{
using
(ServiceHost host =
new
ServiceHost(
typeof
(HelloService)))
{
host.Opened += (s, e) => { Console.WriteLine(
"HelloService已经启动,按按回车键终止服务!"
); };
host.Open();
Console.ReadLine();
}
}
}
}
|
第四步,客户端程序调用WCF服务
注:在客户端程序中首先需要创建或引用WCF服务类库,然后创建实现回调契约的类
实现回调契约:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
using
System;
using
WcfServiceLibrary1;
namespace
ConsoleApplicationClient
{
public
class
HelloCallBack:ICallback
{
public
void
ShowHello(
string
name)
{
Console.WriteLine(
"Hello! {0}.欢迎光临IT文俊社区网,地址:www.zuowenjun.cn"
,name);
}
}
}
|
1.CONFIG文件配置部份:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?
xml
version="1.0" encoding="utf-8" ?>
<
configuration
>
<
system.serviceModel
>
<
bindings
>
<
wsDualHttpBinding
>
<
binding
name="HelloServiceBinding" clientBaseAddress="http://127.0.0.1:10801/HelloServiceCallback"></
binding
>
</
wsDualHttpBinding
>
</
bindings
>
<
client
>
<
endpoint
name="HelloService" address="http://127.0.0.1:10800/HelloService" binding="wsDualHttpBinding" contract="WcfServiceLibrary1.IHello">
</
endpoint
>
</
client
>
</
system.serviceModel
>
</
configuration
>
|
2.代码部份:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
using
System;
using
System.ServiceModel;
using
WcfServiceLibrary1;
namespace
ConsoleApplicationClient
{
class
Program
{
static
void
Main(
string
[] args)
{
CallHelloService();
Console.WriteLine(
"按任意键结束。"
);
Console.Read();
}
static
void
CallHelloService()
{
Console.Write(
"请输入您的网名:"
);
string
input = Console.ReadLine();
InstanceContext instanceContext =
new
InstanceContext(
new
HelloCallBack());
using
(DuplexChannelFactory<IHello> channel =
new
DuplexChannelFactory<IHello>(instanceContext,
"HelloService"
))
{
IHello proxy = channel.CreateChannel();
using
(proxy
as
IDisposable)
{
proxy.SetName(input);
Console.ReadLine();
//注意这句需保留,目的是为了阻止调用proxy的Dispose方法,因为该方法将会试图关闭底层的TCP连接。由于服务端的回调操作也会使用该TCP连接,如果在回调操作尚未执行完毕就试图关闭网络连接,将会导致回调无法正常执行
}
}
}
}
}
|
这里特别说明一下,建议在定义服务方法时,若没有返回值,建议为方法添加IsOneWay=True特性,可以使客户端不用等待请求回复,虽然设置ConcurrencyMode = ConcurrencyMode.Reentrant,但若采用WINFORM客户端使用,则会出现TIMEOUT错误,具体分析与解决方法,详见:我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案
说明:发表这篇文章参考了如下作者的文章:
文章同步发表于我的个人网站:http://www.zuowenjun.cn/post/2015/03/25/133.html
本文转自 梦在旅途 博客园博客,原文链接:http://www.cnblogs.com/zuowj/p/4366939.html ,如需转载请自行联系原作者