其中,请求/答复模式,在博文:
中进行了详细介绍,此处将主要介绍:单向模式与双工模式。
1、首先,先创建一个WCF应用程序:
创建完成后,目录如下:
2、删除IService1.cs和Serivce1.svc,或者修改名称为:CalculateService.svc与ICalculateService.cs后,显示如下:
3、ICalculateService.cs文件内容如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfDuplexTest
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService”。
[ServiceContract(Namespace = "http://blog.csdn.net/jiankunking",
SessionMode = SessionMode.Required, CallbackContract = typeof(ICalculatorDuplexCallback))]
public interface ICalculateService
{
[OperationContract(IsOneWay = true)]
void GetData(string value);
[OperationContract]
CompositeType Clear();
// TODO: 在此添加您的服务操作
}
/*我们可以看到它有一个ICalculatorDuplexCallback的接口,由于它在ServiceContract中被标记为CallbackContract = typeof(ICalculatorDuplexCallback),所以它用于客户端回调。
* 意即,服务端可以通过此接口中的方法将数据发送给客户端,客户端只需要实现此接口,即可接收到服务端发送过来的消息。*/
public interface ICalculatorDuplexCallback
{
[OperationContract(IsOneWay = true)]
void ComplexCalculate(string result);
[OperationContract]
string GetComplexCalculateResult(string value);
}
// 使用下面示例中说明的数据协定将复合类型添加到服务操作
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
}using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfDuplexTest
{
/*ServiceContract的SessionMode
用于Contract上的枚举, 3种:
Allowed: 指定协定永支持会话
Required:指定协定必须会话绑定,否则将引发异常。BasicHttpBinding不支持会话,所以当使用BasicHttpBinding的时候毕会异常;
NotAllowed:指定协定永不支持启动会话的绑定。*/
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Service”。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class CalculateService : ICalculateService
{
//声明一个ICalculatorDuplexCallback接口的对象
ICalculatorDuplexCallback callback = null;
//CalculateService类的构造方法
public CalculateService()
{
//实例化一个ICalculatorDuplexCallback
callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
}
public void GetData(string value)
{
//服务端调用客户端的ComplexCalculate方法
callback.ComplexCalculate(value);
}
public CompositeType Clear()
{
CompositeType composite = new CompositeType();
composite.BoolValue = false;
//服务端调用客户端的GetComplexCalculateResult方法
composite.StringValue = "测试回调客户端带有返回值的方法\r\n " + callback.GetComplexCalculateResult("客户端方法:GetComplexCalculateResult");
return composite;
}
}
}5、修改Web.config的配置文件<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<!--WCF应用程序 一下services节点需要自己手动添加-->
<services>
<service name="WcfDuplexTest.CalculateService">
<endpoint address="" binding="wsDualHttpBinding" contract="WcfDuplexTest.ICalculateService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfDuplexTest/CalculateService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
<serviceMetadata httpGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
6、新建winform客户端进行测试7、添加服务端引用:
8、客户端代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using FormTest.CalculateService;
namespace FormTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Construct InstanceContext to handle messages on callback interface
InstanceContext instanceContext = new InstanceContext(new CallbackHandler());
// Create a client
CalculateService.CalculateServiceClient client = new CalculateService.CalculateServiceClient(instanceContext);
client.GetData("客户端 传入 参数 测试 GetData");
MessageBox.Show("GetData 调用完成!");
//WCF 数据契约的用途
CompositeType composite = client.Clear();
MessageBox.Show("Clear 调用成功 \r\n" + composite.StringValue);
}
}
/// <summary>
/// 以为能找到服务端里的ICalculatorDuplexCallback接口,谁知道服务端的接口ICalculatorDuplexCallback
/// 是ICalculateServiceCallback的形式出现在客户端的
/// </summary>
//修改回调回调函数的通知线程,将其改为在非UI线程中执行。
//WCF中可以通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为
//从而解决UI死锁问题
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
public class CallbackHandler : CalculateService.ICalculateServiceCallback
{
public void ComplexCalculate(string result)
{
MessageBox.Show(result.ToString());
}
public string GetComplexCalculateResult(string result)
{
return result;
}
}
}
死锁具体分析可以参考:点击打开链接
demo代码:点击打开链接
版权声明:作者:jiankunking 出处:http://blog.csdn.net/jiankunking 本文版权归作者和CSDN共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
原文地址:http://blog.csdn.net/jiankunking/article/details/46967553