WCF 雙工模式,wcf雙工模式

來源:互聯網
上載者:User

WCF 雙工模式,wcf雙工模式
WCF之訊息模式分為:
1、請求/回覆模式
2、單向模式
3、雙工模式

其中,請求/回覆模式,在博文:

 WCF 入門教程一(動手建立第一個WCF程式並部署)

WCF 入門教程二

中進行了詳細介紹,此處將主要介紹:單向模式與雙工模式。

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>  </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;        }    }}

小註:
在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: 



著作權聲明:作者:jiankunking 出處:http://blog.csdn.net/jiankunking 本文著作權歸作者和CSDN共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.