博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WCF 双工模式
阅读量:6511 次
发布时间:2019-06-24

本文共 9533 字,大约阅读时间需要 31 分钟。

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
(); } 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的配置文件

6、新建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);        }    }    ///     /// 以为能找到服务端里的ICalculatorDuplexCallback接口,谁知道服务端的接口ICalculatorDuplexCallback    /// 是ICalculateServiceCallback的形式出现在客户端的    ///     //修改回调回调函数的通知线程,将其改为在非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:

小注:

你可能感兴趣的文章