单向(One-Way)操作没有返回值,客户端也不会关心调用成功与否,是一种即发即弃的调用方式,通过使用OperationContractAttribute将操作标记为One-Way,在WSDL描述中只包括<input>消息,服务端抛出的任何异常,都不会传递给客户端。理想状态下,一旦客户端调用了一个单向方法,它只会在分发调用的一瞬间被阻塞。但实事上,单向调用并不等同于异步调用。当单向调用到达服务端时,不会立即分发这些调用,而是可能放入到服务端的队列中,并在某个时间被分发。这一过程与服务配置的并发模式行为、队列中的最大消息个数、配置的通道以及可靠性有关。如果队列消息数量超过了队列容量,应会阻塞客户端。然而,一旦调用被放入队列,就会取消对客户端的阻塞。所有的WCF绑定都支持单向操作。
虽然服务端抛出的任何异常,都不会传递给客户端,然而,在分发一个单向操作时,因为通信问题(例如地址错误或宿主不可用)导致在分发调用时出现的错误,在试图调用操作时,会在客户端抛出一个异常。
在单调服务中,如果没有传输会话,当调用一个单向操作时,如果发生异常,客户端并不会受到影响,继续发出对相同代理实例的调用。但是如果使用具有安全性的WSHttpBinding绑定,或者使用不包含可靠性消息传输的NetTcpBinding和NetNamedPipeBinding绑定,那么一个服务端的异常,包括单向操作抛出的异常,就会导致通道错误,此时,客户端不能发出任何一个使用相同代理实例的新的调用,客户端甚至不能安全的关闭代理。在使用可靠消息传输的WSHttpBinding绑定或者NetTcpBinding时,异常不会导致通道错误,此时,客户端能够继续发出调用。
单向操作应用的场景主要为:Fire-and-forget,不需要报告成功与否的操作,如:日志活动或事件发布;Polling,客户端通过一个请求来获得长时间运行的操作的结果;Duplex,One-Way操作特别适用于当涉及到回调操作时的双向通讯。
下面,我们通过一个DEMO来介绍单向操作:
主要代码如下:
契约接口代码:
[ServiceContract(Namespace = "http://schemas.xinhaijulan.com/demos/OneWay")]
public interface IMyContract
{
[OperationContract(IsOneWay = true)]
void MethodWithError();
[OperationContract]
void MethodWithoutError();
}
实现类代码:
public class MyContract : IMyContract
{
public void MethodWithError()
{
Console.WriteLine("Execute MethodWithError");
throw new Exception();
}
public void MethodWithoutError()
{
Console.WriteLine("Execute MethodWithoutError");
}
}
服务端代码:
static void Main(string[] args)
{
StartBasicHttpBindingServer();
//StartNetTcpBindingServer();
}
private static void StartBasicHttpBindingServer()
{
using (ServiceHost host = new ServiceHost(typeof(ServiceLibrary.MyContract)))
{
host.AddServiceEndpoint(typeof(ServiceLibrary.IMyContract), new BasicHttpBinding(), "http://localhost:8001/MyContract");
host.Open();
Console.WriteLine("Please input exit to close host.");
string key = Console.ReadLine();
while (key.ToLower() != "exit")
{
Console.WriteLine("Please input exit to close host.");
key = Console.ReadLine();
}
}
}
private static void StartNetTcpBindingServer()
{
using (ServiceHost host = new ServiceHost(typeof(ServiceLibrary.MyContract)))
{
host.AddServiceEndpoint(typeof(ServiceLibrary.IMyContract), new NetTcpBinding(), "net.tcp://localhost:9001/MyContract");
host.Open();
Console.WriteLine("Please input exit to close host.");
string key = Console.ReadLine();
while (key.ToLower() != "exit")
{
Console.WriteLine("Please input exit to close host.");
key = Console.ReadLine();
}
}
}
客户端代码:
static void Main(string[] args)
{
TestBasicHttpBinding();
//TestNetTcpBinding();
Console.ReadLine();
}
private static void TestBasicHttpBinding()
{
ChannelFactory<ServiceLibrary.IMyContract> channelFactory = new ChannelFactory<ServiceLibrary.IMyContract>(new BasicHttpBinding());
ServiceLibrary.IMyContract client = channelFactory.CreateChannel(new EndpointAddress("http://localhost:8001/MyContract"));
using (client as IDisposable)
{
Console.WriteLine("------------TestBasicHttpBinding Begin-------------");
client.MethodWithError();
client.MethodWithoutError();
Console.WriteLine("------------TestBasicHttpBinding End---------------");
}
}
private static void TestNetTcpBinding()
{
ChannelFactory<ServiceLibrary.IMyContract> channelFactory = new ChannelFactory<ServiceLibrary.IMyContract>(new NetTcpBinding());
ServiceLibrary.IMyContract client = channelFactory.CreateChannel(new EndpointAddress("net.tcp://localhost:9001/MyContract"));
using (client as IDisposable)
{
Console.WriteLine("------------TestNetTcpBinding Begin-------------");
client.MethodWithError();
client.MethodWithoutError();
Console.WriteLine("------------TestNetTcpBinding End---------------");
}
}
A:测试BasicHttpBinding
首页在服务端开启:StartBasicHttpBindingServer()方法,注释StartNetTcpBindingServer()方法,在客户端开启TestBasicHttpBinding()方法,注释TestNetTcpBinding()方法,然后,先启动服务端,再启动客户端,可以看到输出如下:
服务端输出:
Please input exit to close host.
Execute MethodWithoutError
Execute MethodWithError
客户端输出:
------------TestBasicHttpBinding Begin-------------
------------TestBasicHttpBinding End---------------
这说明没有传输会话时,服务端的异常不会传递给客户端,在服务端抛出异常后,客户端仍旧可以正常执行。
B:测试NetTcpBinding
首页在服务端开启:StartNetTcpBindingServer()方法,注释StartBasicHttpBindingServer()方法,在客户端开启TestNetTcpBinding()方法,注释TestBasicHttpBinding()方法,然后,先启动服务端,再启动客户端,可以看到输出如下:
服务端输出:
Please input exit to close host.
Execute MethodWithError
客户端输出:
------------TestNetTcpBinding Begin-------------
同时客户端在使用相同代理进行新的调用时,抛出了错误,截图如下:
这说明使用不包含可靠性消息传输的NetTcpBinding和NetNamedPipeBinding绑定,那么一个服务端的异常,包括单向操作抛出的异常,就会导致通道错误。
至此,单向操作介绍完毕。
作者:心海巨澜
出处:http://xinhaijulan.cnblogs.com
版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。