wcf中的契约通信默认是请求恢复的方式,当客户端发出请求后,一直到服务端回复时,才可以继续执行下面的代码。
除了使用请求应答方式的通信外,还可以使用全双工。下面给出例子:
1.添加一个wcf类库
2.在服务契约添加如下一个片段
[ServiceContract(Namespace = ", SessionMode = SessionMode.Required,
CallbackContract = typeof(ICalculatorDuplexCallback))]public interface ICalculatorDuplex
{ [OperationContract(IsOneWay = true)] void Clear(); [OperationContract(IsOneWay = true)] void AddTo(double n); [OperationContract(IsOneWay = true)] void SubtractFrom(double n); [OperationContract(IsOneWay = true)] void MultiplyBy(double n); [OperationContract(IsOneWay = true)] void DivideBy(double n); }其中ICalculatorDuplexCallback为实现全双工客户端的接口
3.定义ICalculatorDuplexCallback接口。该接口目的主要是回调客户端的方法。和服务端无关,所以让该接口的方法设置为单向的
public interface ICalculatorDuplexCallback
{ [OperationContract(IsOneWay = true)] void Equals(double result); [OperationContract(IsOneWay = true)] void Equation(string eqn); } 4.由于回话是必须的,那么在契约实现的时候也要加上一个特性[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Service1 : IService1
{ double result; string equation; ICalculatorDuplexCallback callback = null;public Service1()
{ result = 0.0D; equation = result.ToString(); callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>(); }public void Clear()
{ callback.Equation(equation + " = " + result.ToString()); result = 0.0D; equation = result.ToString(); }public void AddTo(double n)
{ result += n; equation += " + " + n.ToString(); callback.Equals(result); }public void SubtractFrom(double n)
{ result -= n; equation += " - " + n.ToString(); callback.Equals(result); }public void MultiplyBy(double n)
{ result *= n; equation += " * " + n.ToString(); callback.Equals(result); }public void DivideBy(double n)
{ result /= n; equation += " / " + n.ToString(); callback.Equals(result); } }5.接着在项目中添加一个控制台程序,添加服务。服务会报异常
System.InvalidOperationException: 协定需要会话,但是绑定“BasicHttpBinding”不支持它或者因配置不正确而无法支持它。
在 System.ServiceModel.Description.DispatcherBuilder.BuildChannelListener(StuffPerListenUriInfo stuff, ServiceHostBase serviceHost, Uri listenUri, ListenUriMode listenUriMode, Boolean supportContextSession, IChannelListener& result) 在 System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) 在 System.ServiceModel.ServiceHostBase.InitializeRuntime() 在 System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) 在 System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) 在 Microsoft.Tools.SvcHost.ServiceHostHelper.OpenService(ServiceInfo info)需要把服务端配置文件中改一下:
<system.serviceModel>
<services> <service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior"> <!-- Service Endpoints --> <!-- 除非完全限定,否则地址将与上面提供的基址相关 --> <endpoint address="" binding="wsDualHttpBinding" contract="WcfService1.IService1"> <!-- 部署时,应删除或替换下列标识元素,以反映 用来运行所部署服务的标识。删除之后,WCF 将 自动推断相应标识。 --> <identity> <dns value="localhost"/> </identity> </endpoint> <!-- Metadata Endpoints --> <!-- 元数据交换终结点供相应的服务用于向客户端做自我介绍。 --> <!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除--> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfService1.Service1Behavior"> <!-- 为避免泄漏元数据信息, 请在部署前将以下值设置为 false --> <serviceMetadata httpGetEnabled="False" httpsGetEnabled="False"/> <!-- 要接收故障异常详细信息以进行调试, 请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息--> <serviceDebug includeExceptionDetailInFaults="True" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>6.在控制台端,添加服务引用,实现服务定义的ICalculatorDuplexCallback接口(该接口自动生成的对应到服务引用中的IService1Callback)
public class CallbackHandler : IService1Callback
{ public void Equals(double result) { Console.WriteLine("Result({0})", result); }public void Equation(string eqn)
{ Console.WriteLine("Equation({0})", eqn); } }7.在main函数中,去调用服务
InstanceContext instanceContext = new InstanceContext(new CallbackHandler());
// Create a client
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(instanceContext);Console.WriteLine("Press <ENTER> to terminate client once the output is displayed.");
Console.WriteLine();// Call the AddTo service operation.
double value = 100.00D; client.AddTo(value);// Call the SubtractFrom service operation.
value = 50.00D; client.SubtractFrom(value);// Call the MultiplyBy service operation.
value = 17.65D; client.MultiplyBy(value);// Call the DivideBy service operation.
value = 2.00D; client.DivideBy(value);// Complete equation
client.Clear();Console.ReadLine();
//Closing the client gracefully closes the connection and cleans up resources
client.Close();8.运行结果