• WCF 双工模式


    WCF之消息模式分为:
    1、请求/答复模式
    2、单向模式
    3、双工模式

    其中,请求/答复模式,在博文:

     WCF 入门教程一(动手新建第一个WCF程序并部署)

    WCF 入门教程二

    中进行了详细介绍,此处将主要介绍:单向模式与双工模式。

    1、首先,先创建一个WCF应用程序:

    创建完成后,目录如下:

    2、删除IService1.cs和Serivce1.svc,或者修改名称为:CalculateService.svc与ICalculateService.cs后,显示如下:

    3、ICalculateService.cs文件内容如下:

    [csharp] view plaincopy
     
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Runtime.Serialization;  
    5. using System.ServiceModel;  
    6. using System.ServiceModel.Web;  
    7. using System.Text;  
    8.   
    9. namespace WcfDuplexTest  
    10. {  
    11.     // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService”。  
    12.     [ServiceContract(Namespace = "http://blog.csdn.net/jiankunking",  
    13.      SessionMode = SessionMode.Required, CallbackContract = typeof(ICalculatorDuplexCallback))]  
    14.     public interface ICalculateService  
    15.     {  
    16.         [OperationContract(IsOneWay = true)]  
    17.         void GetData(string value);  
    18.   
    19.         [OperationContract]  
    20.         CompositeType Clear();  
    21.   
    22.         // TODO: 在此添加您的服务操作  
    23.     }  
    24.   
    25.     /*我们可以看到它有一个ICalculatorDuplexCallback的接口,由于它在ServiceContract中被标记为CallbackContract = typeof(ICalculatorDuplexCallback),所以它用于客户端回调。 
    26.     * 意即,服务端可以通过此接口中的方法将数据发送给客户端,客户端只需要实现此接口,即可接收到服务端发送过来的消息。*/  
    27.     public interface ICalculatorDuplexCallback  
    28.     {  
    29.         [OperationContract(IsOneWay = true)]  
    30.         void ComplexCalculate(string result);  
    31.         [OperationContract]  
    32.         string GetComplexCalculateResult(string value);  
    33.   
    34.     }  
    35.   
    36.     // 使用下面示例中说明的数据协定将复合类型添加到服务操作  
    37.     [DataContract]  
    38.     public class CompositeType  
    39.     {  
    40.         bool boolValue = true;  
    41.         string stringValue = "Hello ";  
    42.   
    43.         [DataMember]  
    44.         public bool BoolValue  
    45.         {  
    46.             get { return boolValue; }  
    47.             set { boolValue = value; }  
    48.         }  
    49.   
    50.         [DataMember]  
    51.         public string StringValue  
    52.         {  
    53.             get { return stringValue; }  
    54.             set { stringValue = value; }  
    55.         }  
    56.     }  
    57. }  


    4、CalculateService.svc文件中的内容:

    [csharp] view plaincopy
     
    1. <pre name="code" class="csharp">using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Runtime.Serialization;  
    5. using System.ServiceModel;  
    6. using System.ServiceModel.Web;  
    7. using System.Text;  
    8.   
    9. namespace WcfDuplexTest  
    10. {  
    11.     /*ServiceContract的SessionMode 
    12.     用于Contract上的枚举, 3种: 
    13.     Allowed: 指定协定永支持会话 
    14.     Required:指定协定必须会话绑定,否则将引发异常。BasicHttpBinding不支持会话,所以当使用BasicHttpBinding的时候毕会异常; 
    15.     NotAllowed:指定协定永不支持启动会话的绑定。*/  
    16.     // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Service”。  
    17.     [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]  
    18.     public class CalculateService : ICalculateService  
    19.     {  
    20.         //声明一个ICalculatorDuplexCallback接口的对象  
    21.         ICalculatorDuplexCallback callback = null;  
    22.         //CalculateService类的构造方法  
    23.         public CalculateService()  
    24.         {  
    25.             //实例化一个ICalculatorDuplexCallback  
    26.             callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();  
    27.         }  
    28.   
    29.         public void GetData(string value)  
    30.         {  
    31.             //服务端调用客户端的ComplexCalculate方法  
    32.             callback.ComplexCalculate(value);  
    33.         }  
    34.   
    35.         public CompositeType Clear()  
    36.         {  
    37.             CompositeType composite = new CompositeType();  
    38.             composite.BoolValue = false;  
    39.             //服务端调用客户端的GetComplexCalculateResult方法  
    40.             composite.StringValue = "测试回调客户端带有返回值的方法  " + callback.GetComplexCalculateResult("客户端方法:GetComplexCalculateResult");  
    41.             return composite;  
    42.         }  
    43.   
    44.     }  
    45. }</pre>  

    5、修改Web.config的配置文件

    [html] view plaincopy
     
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <configuration>  
    3.   
    4.   <system.web>  
    5.     <compilation debug="true" targetFramework="4.0" />  
    6.   </system.web>  
    7.   <system.serviceModel>  
    8.     <!--WCF应用程序 一下services节点需要自己手动添加-->  
    9.     <services>  
    10.       <service name="WcfDuplexTest.CalculateService">  
    11.         <endpoint address="" binding="wsDualHttpBinding" contract="WcfDuplexTest.ICalculateService">  
    12.           <identity>  
    13.             <dns value="localhost" />  
    14.           </identity>  
    15.         </endpoint>  
    16.         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />  
    17.         <host>  
    18.           <baseAddresses>  
    19.             <add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfDuplexTest/CalculateService/" />  
    20.           </baseAddresses>  
    21.         </host>  
    22.       </service>  
    23.     </services>  
    24.     <behaviors>  
    25.       <serviceBehaviors>  
    26.         <behavior>  
    27.           <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->  
    28.           <serviceMetadata httpGetEnabled="true"/>  
    29.           <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->  
    30.           <serviceDebug includeExceptionDetailInFaults="true"/>  
    31.         </behavior>  
    32.       </serviceBehaviors>  
    33.     </behaviors>  
    34.     <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />  
    35.   </system.serviceModel>  
    36.  <system.webServer>  
    37.     <modules runAllManagedModulesForAllRequests="true"/>  
    38.   </system.webServer>  
    39.     
    40. </configuration>  

    6、新建winform客户端进行测试

    7、添加服务端引用:


    小注:

    今天在vs2015中新建WCF类库,又能找到服务了惊恐

    8、客户端代码如下:

    [csharp] view plaincopy
     
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.ComponentModel;  
    4. using System.Data;  
    5. using System.Drawing;  
    6. using System.Linq;  
    7. using System.Text;  
    8. using System.Windows.Forms;  
    9. using System.ServiceModel;  
    10. using FormTest.CalculateService;  
    11.   
    12. namespace FormTest  
    13. {  
    14.     public partial class Form1 : Form  
    15.     {  
    16.         public Form1()  
    17.         {  
    18.             InitializeComponent();  
    19.         }  
    20.         private void button1_Click(object sender, EventArgs e)  
    21.         {  
    22.             // Construct InstanceContext to handle messages on callback interface  
    23.             InstanceContext instanceContext = new InstanceContext(new CallbackHandler());  
    24.             // Create a client  
    25.             CalculateService.CalculateServiceClient client = new CalculateService.CalculateServiceClient(instanceContext);  
    26.   
    27.             client.GetData("客户端 传入 参数 测试 GetData");  
    28.             MessageBox.Show("GetData 调用完成!");  
    29.   
    30.             //WCF 数据契约的用途  
    31.             CompositeType composite = client.Clear();  
    32.             MessageBox.Show("Clear 调用成功  " + composite.StringValue);  
    33.         }  
    34.     }  
    35.   
    36.   
    37.     /// <summary>  
    38.     /// 以为能找到服务端里的ICalculatorDuplexCallback接口,谁知道服务端的接口ICalculatorDuplexCallback  
    39.     /// 是ICalculateServiceCallback的形式出现在客户端的  
    40.     /// </summary>  
    41.     //修改回调回调函数的通知线程,将其改为在非UI线程中执行。  
    42.     //WCF中可以通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为  
    43.     //从而解决UI死锁问题  
    44.     [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]  
    45.     public class CallbackHandler : CalculateService.ICalculateServiceCallback  
    46.     {  
    47.         public void ComplexCalculate(string result)  
    48.         {  
    49.             MessageBox.Show(result.ToString());  
    50.         }  
    51.   
    52.         public string GetComplexCalculateResult(string result)  
    53.         {  
    54.             return result;  
    55.         }  
    56.     }  
    57. }  


    小注:
    在WCF回调中需要注意死锁问题
    1、如果WCF中暴露出来的操作,没有返回值,则可以通过就是设置回调操作
    IsOneWay=true,这样回调以后立即释放服务实例,不需要等待客户端响应消息,也可以避免死锁。
    2、如果WCF中暴露出来的操作,有返回值,则需要通过,修改服务的ServiceBehavior的ConcurrencyMode为Reentrant或Multiple即可。
    此时,服务端的死锁问题搞定了。
    下面就需要考虑客户端的死锁问题了
    客户端的死锁问题,通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为

    死锁具体分析可以参考:点击打开链接

    demo代码:点击打开链接

    服务端死锁时的提示信息:

    [plain] view plaincopy
     
    1. 未处理 System.ServiceModel.FaultException`1  
    2.   HResult=-2146233087  
    3.   Message=此操作将死锁,因为在当前邮件完成处理以前无法收到答复。如果要允许无序的邮件处理,则在 ServiceBehaviorAttribute 上指定可重输入的或多个 ConcurrencyMode。  
    4.   Source=mscorlib  
    5.   Action=http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher/fault  
    6.   StackTrace:  
    7.     Server stack trace:   
    8.        在 System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)  
    9.        在 System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)  
    10.        在 System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)  
    11.        在 System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)  
    12.        在 System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)  
    13.     Exception rethrown at [0]:   
    14.        在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)  
    15.        在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)  
    16.        在 FormTest.CalculateService.ICalculateService.GetData(Int32 value)  
    17.        在 FormTest.CalculateService.CalculateServiceClient.GetData(Int32 value) 位置 E:WorkSpaceWorkSpaceTestWcfDuplexTestFormTestService ReferencesCalculateServiceReference.cs:行号 124  
    18.        在 FormTest.Form1.button1_Click(Object sender, EventArgs e) 位置 E:WorkSpaceWorkSpaceTestWcfDuplexTestFormTestForm1.cs:行号 27  
    19.        在 System.Windows.Forms.Control.OnClick(EventArgs e)  
    20.        在 System.Windows.Forms.Button.OnClick(EventArgs e)  
    21.        在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)  
    22.        在 System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)  
    23.        在 System.Windows.Forms.Control.WndProc(Message& m)  
    24.        在 System.Windows.Forms.ButtonBase.WndProc(Message& m)  
    25.        在 System.Windows.Forms.Button.WndProc(Message& m)  
    26.        在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)  
    27.        在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)  
    28.        在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)  
    29.        在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)  
    30.        在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)  
    31.        在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)  
    32.        在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)  
    33.        在 System.Windows.Forms.Application.Run(Form mainForm)  
    34.        在 FormTest.Program.Main() 位置 E:WorkSpaceWorkSpaceTestWcfDuplexTestFormTestProgram.cs:行号 18  
    35.        在 System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)  
    36.        在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)  
    37.        在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()  
    38.        在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)  
    39.        在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)  
    40.        在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)  
    41.        在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)  
    42.        在 System.Threading.ThreadHelper.ThreadStart()  
    43.   InnerException:   



    小注:

  • 相关阅读:
    asp.net 遍历xml 及 Repeater 绑定xml
    通过NetworkIsolationEnumAppContainers查看安装的UWP应用
    修复 Outlook 数据文件(.pst 和 .ost)
    c# 学习笔记 抓包解析器开发
    c++ 结构体位域操作 进制转换
    《C++ Footprint and Performance Optimization》读书笔记
    SQL SERVER 2000 函数一点小注意
    一个B/S结构MIS的登录日志的问题。
    jmeter连接mysql提示Cannot create PoolableConnectionFactory(查看jmeter日志,提示SSL)如何解决
    List、Map、Set之间的联系与区别:
  • 原文地址:https://www.cnblogs.com/Alex80/p/5133218.html
Copyright © 2020-2023  润新知