在WCF通信中,如果实现要得到服务端处理的结果,一种方式是在契约中指定调用方法带返回值(IsOneWay=false),但这种方式是有缺陷的,如果服务端处理时间过长,则客户端也需要长时间等待。
另一种方式是通过双工通信,使用回调来实现。但回调的时候,回调方法中不应该有耗时操作,否则当服务端处理完成退出的时间,回调消息会丢失。
目前WCF支持双工的绑定方式有:WSDualHttpBinding,NetTcpBinding与NetNamedPipeBinding三种,其它绑定方式不支持双工。
下面以一个简短的例子说明双工通信。
1、定义契约
-
[ServiceContract(Namespace = "http://cnblog.com/zhili/", CallbackContract = typeof(ICallback))]
-
public interface ICalculator
-
{
-
[OperationContract(IsOneWay = true)]
-
void Multiple(double a, double b);
-
[OperationContract(IsOneWay = true)]
-
void DisplayString(string name);
-
}
其中指定了回调契约是ICallback。
-
// 回调契约的定义,此时回调契约不需要应用ServiceContractAttribute特性
-
public interface ICallback
-
{
-
[OperationContract(IsOneWay = true)]
-
void DisplayResult(double x, double y, double result);
-
-
[OperationContract(IsOneWay = false, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
-
string DisplayStringResult(string retStr);
-
}
我们看到,回调第二个方法有返回值。这个在服务行为配置中要有特殊配置,否则会卡死。
2、服务端实现
实现服务契约:
-
// 服务契约的实现
-
[ServiceBehavior(IncludeExceptionDetailInFaults = true,ConcurrencyMode = ConcurrencyMode.Multiple)]
-
public class CalculatorService : ICalculator
-
{
-
#region ICalculator Members
-
-
public void Multiple(double a, double b)
-
{
-
for (int i = 1; i < 100; i++)
-
{
-
double result = a * b;
-
-
// 通过客户端实例通道
-
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
-
-
// 对客户端操作进行回调
-
callback.DisplayResult(a, b, result);
-
Console.WriteLine("Callback Times {0} at time {1}", i, DateTime.Now.ToString("hh:mm:ss tt zz"));
-
}
-
Program.ExitFlag = true;
-
}
-
-
public void DisplayString(string name)
-
{
-
-
for (int i = 1; i < 100; i++)
-
{
-
// 通过客户端实例通道
-
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
-
-
// 对客户端操作进行回调
-
string retStr = callback.DisplayStringResult("Hello " + name);
-
Console.WriteLine("Callback Times {0} at time {1}, ret={2}", i, DateTime.Now.ToString("hh:mm:ss tt zz"), retStr);
-
}
-
Program.ExitFlag = true;
-
}
-
-
#endregion
-
}
其中ServiceBehavior属性的ConcurrencyMode =
ConcurrencyMode.Multiple配置就是配置回调方法带返回值问题(IsOneWay=false),如果不设置这个属性,或者设置为Single,上述回调方法调用时会卡死。
主程序如下:
-
class Program
-
{
-
public static bool ExitFlag = false;
-
static void Main(string[] args)
-
{
-
using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
-
{
-
host.Opened += delegate
-
{
-
Console.WriteLine("Service start now....");
-
};
-
-
host.Open();
-
while (!ExitFlag)
-
{
-
Thread.Sleep(500);
-
}
-
}
-
}
-
}
主程序配置(App.Config):
-
<?xml version="1.0" encoding="utf-8" ?>
-
<configuration>
-
<system.serviceModel>
-
<behaviors>
-
<serviceBehaviors>
-
<behavior>
-
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
-
</behavior>
-
</serviceBehaviors>
-
</behaviors>
-
<services>
-
<service name="NMS.WCFDemo.Server.CalculatorService">
-
<endpoint address="net.tcp://localhost:9003/CalculatorService" binding="netTcpBinding" contract="NMS.WCFDemo.Contract.ICalculator"/>
-
</service>
-
</services>
-
</system.serviceModel>
-
</configuration>
3、客户端
创建完客户端程序后,添加一个服务引用,指向上面配置文件的地址获取服务引用。(添加服务引用时服务程序必须已经在运行)
实现回调契约:
-
// 客户端中对回调契约的实现
-
public class CallbackWCFService : ICalculatorCallback
-
{
-
private int i = 1;
-
public void DisplayResult(double a, double b, double result)
-
{
-
Console.WriteLine("{4} : {0} * {1} = {2} ====== AT Time {3}", a, b, result, DateTime.Now.ToString("hh:mm:ss tt zz"), i++);
-
Thread.Sleep(1000);
-
}
-
-
public string DisplayStringResult(string retStr)
-
{
-
Console.WriteLine("{0} : recevie msg {1} ====== AT Time {2}", i++, retStr, DateTime.Now.ToString("hh:mm:ss tt zz"));
-
Thread.Sleep(1000);
-
return i.ToString();
-
}
-
}
客户端主程序:
-
// 客户端实现,测试回调操作
-
class Program
-
{
-
static void Main(string[] args)
-
{
-
InstanceContext instanceContex = new InstanceContext(new CallbackWCFService());
-
CalculatorClient proxy = new CalculatorClient(instanceContex);
-
if (args[0] == "1")
-
{
-
proxy.Multiple(2, 3);
-
}
-
else
-
{
-
Console.WriteLine("Call string ...");
-
proxy.DisplayString("Client");
-
}
-
Console.Read();
-
}
-
}
客户端配置文件(App.Config)
-
<?xml version="1.0" encoding="utf-8" ?>
-
<configuration>
-
<startup>
-
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
-
</startup>
-
<system.serviceModel>
-
<bindings>
-
<netTcpBinding>
-
<binding name="NetTcpBinding_ICalculator" />
-
<binding name="NetTcpBinding_ICalculator1" />
-
</netTcpBinding>
-
</bindings>
-
<client>
-
<endpoint address="net.tcp://localhost:9003/CalculatorService"
-
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculator"
-
contract="NMS.WCFDemo.Contract.ICalculator" name="NetTcpBinding_ICalculator" />
-
<endpoint address="net.tcp://localhost:9003/CalculatorService"
-
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculator1"
-
contract="ServiceReference1.ICalculator" name="NetTcpBinding_ICalculator1">
-
<identity>
-
<userPrincipalName value="DESKTOP-4D9M16H\wangcc" />
-
</identity>
-
</endpoint>
-
</client>
-
</system.serviceModel>
-
</configuration>
然后运行程序就能看到效果了。
阅读(3761) | 评论(0) | 转发(0) |