WCF 双工模式
2023-09-14 09:02:13 时间
作者:jiankunking 出处:http://blog.csdn.net/jiankunking
WCF之消息模式分为:
1、请求/答复模式2、单向模式
3、双工模式
其中,请求/答复模式,在博文:
中进行了详细介绍,此处将主要介绍:单向模式与双工模式。
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; } }
4、CalculateService.svc文件中的内容:
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 /configuration6、新建winform客户端进行测试
7、添加服务端引用:
小注:
今天在vs2015中新建WCF类库,又能找到服务了
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;
小注:
在WCF回调中需要注意死锁问题
1、如果WCF中暴露出来的操作,没有返回值,则可以通过就是设置回调操作
IsOneWay=true,这样回调以后立即释放服务实例,不需要等待客户端响应消息,也可以避免死锁。
2、如果WCF中暴露出来的操作,有返回值,则需要通过,修改服务的ServiceBehavior的ConcurrencyMode为Reentrant或Multiple即可。
此时,服务端的死锁问题搞定了。
下面就需要考虑客户端的死锁问题了
客户端的死锁问题,通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为
死锁具体分析可以参考:点击打开链接
demo代码:点击打开链接
服务端死锁时的提示信息:
未处理 System.ServiceModel.FaultException`1 HResult=-2146233087 Message=此操作将死锁,因为在当前邮件完成处理以前无法收到答复。如果要允许无序的邮件处理,则在 ServiceBehaviorAttribute 上指定可重输入的或多个 ConcurrencyMode。 Source=mscorlib Action=http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher/fault StackTrace: Server stack trace: 在 System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter) 在 System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc rpc) 在 System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) 在 System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) 在 System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown at [0]: 在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) 在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData msgData, Int32 type) 在 FormTest.CalculateService.ICalculateService.GetData(Int32 value) 在 FormTest.CalculateService.CalculateServiceClient.GetData(Int32 value) 位置 E:\WorkSpace\WorkSpaceTest\WcfDuplexTest\FormTest\Service References\CalculateService\Reference.cs:行号 124 在 FormTest.Form1.button1_Click(Object sender, EventArgs e) 位置 E:\WorkSpace\WorkSpaceTest\WcfDuplexTest\FormTest\Form1.cs:行号 27 在 System.Windows.Forms.Control.OnClick(EventArgs e) 在 System.Windows.Forms.Button.OnClick(EventArgs e) 在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) 在 System.Windows.Forms.Control.WmMouseUp(Message m, MouseButtons button, Int32 clicks) 在 System.Windows.Forms.Control.WndProc(Message m) 在 System.Windows.Forms.ButtonBase.WndProc(Message m) 在 System.Windows.Forms.Button.WndProc(Message m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG msg) 在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) 在 System.Windows.Forms.Application.Run(Form mainForm) 在 FormTest.Program.Main() 位置 E:\WorkSpace\WorkSpaceTest\WcfDuplexTest\FormTest\Program.cs:行号 18 在 System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(Object state) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 在 System.Threading.ThreadHelper.ThreadStart() InnerException:
小注:
wcf双工通讯 首先说一个服务引用不成功的解决办法: 需要把服务端配置文件中的Binding换成: 下面是一个wcf的简单示例: 服务契约代码: using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace WcfService // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IUser”。
相关文章
- VIsual Studio2017中创建WCF服务时找不到问题
- .NET/ASP.NET/C#/WCF/SQL Server/My SQL/Java/JSP/JDBC/Spring/Spring MVC/PHP/Python/Ruby/Shell/Agile/CSS/HTML/HTTP/Unix/Linux大量PDF书籍/电子书籍下载, Effective Java 下载详解编程语言
- 多用途的Linux下的WCF应用(linuxwcf)
- 让WCF支持Linux环境(wcflinux)
- 微软开源了WCF框架
- Nginx搭建高可用,高并发的WCF集群教程
- 使用 WCF 和 Oracle 搭建企业数据服务的实现(wcf oracle)
- WCF与Redis的联系挖掘共赢的可能性(wcf和redis的联系)
- jquery调用wcf并展示出数据的方法
- C#一个WCF简单实例
- 在IIS8服务器添加WCF服务支持的方法
- WinForm窗体调用WCF服务窗体卡死问题
- IIS8中添加WCF支持几种方法小结[图文]
- 关于.NET/C#/WCF/WPF打造IP网络智能视频监控系统的介绍
- 解析Silverlight调用WCF/Rest异常的解决方法
- IIS7配置大全(ASP.NET2.0,WCF,ASP.NETMVC,php)
- jQueryajax调用WCF服务实例
- 在WCF数据访问中使用缓存提高Winform字段中文显示速度的方法