20181102_WCF簡單雙工
- 使用管理員許可權開啟VS2017
2. 建立一個空白解決方案:
3. 建立幾個基於.net framework的類庫專案和一個基於.net Framework 的控制檯專案, 然後將類庫專案的class1.cs檔案刪除, 整體如下圖:
4. 為每個類庫新增對應的類檔案:
a) MyWCF.WCFSimpleDuplex.Interface新增兩個介面, ICalculatorService和ICallBack, 其中ICalculatorService表示要啟動的服務介面, 而ICallBack表示要回調客戶端時, 訪問的介面
b) ICalculatorService 程式碼如下:
using System.ServiceModel; namespace MyWCF.WCFSimpleDuplex.Interface { /// <summary> /// 定義協議的時候, 同時需要定義一個回撥介面 /// 示例中定義服務契約的同時定義一個回撥介面ICallBack /// 雙工中的函式不能帶返回值 /// 如果你實在想要返回值, 那麼自己用out /// </summary> [ServiceContract(CallbackContract = typeof(ICallBack))] public interface ICalculatorService { /// <summary> /// 新增isoneway屬性表示, 這個函式是不是返回應答資訊 ; /// </summary> /// <param name="x"></param> /// <param name="y"></param> [OperationContract(IsOneWay = true)] void Plus(int x, int y); //建立了一個Icalculator服務的協議 //這個協議帶有一個回撥介面ICallBack //注意WCF的雙工, 不能全靠配置, 在建立服務的時候, 就要開始處理了 } }
c) ICallBack程式碼如下
using System.ServiceModel; namespace MyWCF.WCFSimpleDuplex.Interface { /// <summary> /// 不需要協議, 因為它不是一個服務契約, 它只是一個約束,這個約束由客戶端實現 /// </summary> public interface ICallBack { /// <summary> /// 這裡就是回撥的時候完成的函式, 這個介面也要加上Isoneway=true /// </summary> /// <param name="m"></param> /// <param name="n"></param> /// <param name="result"></param> [OperationContract(IsOneWay = true)] void Show(int m, int n, int result); } //要釋出一個雙工協議 ,首先在服務的建立WCF服務, 服務的契約上面指定callbackContract回撥的型別 //建立回撥介面, 回撥介面就是等下要執行的介面 }
5. 接下來處理 MyWCF.WCFSimpleDuplex.Model 的程式碼, 它就一個類:
using System.Runtime.Serialization; namespace MyWCF.WCFSimpleDuplex.Model { [DataContract] public class WCFUser { //[DataMember] public int Id { get; set; } [DataMember] public int Age { get; set; } [DataMember] public int Sex { get; set; } [DataMember] public string Name { get; set; } [DataMember] public string Description { get; set; } } public enum WCFUserSex { Famale, Male, Other } }
6. 關於服務類MyWCF.WCFSimpleDuplex.Service的處理如下:
using System.ServiceModel; using MyWCF.WCFSimpleDuplex.Interface; namespace MyWCF.WCFSimpleDuplex.Service { /// <summary> /// 對ICalculatorService的一個實現類; 實現的時候, 除了要完成自己的計算, 還要完成, 對介面的回撥 /// </summary> public class CalculatorService : ICalculatorService { /// <summary> /// 完成計算,然後去回撥 /// </summary> /// <param name="x"></param> /// <param name="y"></param> public void Plus(int x, int y) { int result = x + y; System.Threading.Thread.Sleep(3000); //OperationContext表示當前操作的上下文 //OperationContext.Current.GetCallbackChannel<ICallBack>();這裡有點像IOC, 給你一個介面然後生成一個例項; 注意哦, 這裡的ICallBack還有沒有任何實現, 而這個實現是在客戶端(client)處去完成的 ICallBack callBack =OperationContext.Current.GetCallbackChannel<ICallBack>(); callBack.Show(x, y, result); } } }
7. 接下來是控制檯MyWCF.WCFSimpleDuplex.ConsoleTest的程式碼實現, 首先是他的配置檔案
a) 初始時的配置檔案如下圖:
b) 在configuration節點新增如下配置:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <system.serviceModel> <!--WCF的配置檔案 , WCF的配置檔案一個是基於TCP的, 一個是基於http的; 可以新增多個; 如果新增多個就是下面的配置格式 --> <behaviors> <serviceBehaviors> <!--<behavior name="MathServicebehavior"> --><!--這裡配置第一個Behavior的節點--><!-- <serviceDebug httpHelpPageEnabled="false"/> <serviceMetadata httpGetEnabled="false"/> <serviceTimeouts transactionTimeout="00:10:00"/> <serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/> </behavior>--> <behavior name="CalculatorServicebehavior"> <!--這裡配置第二個Behavior的節點--> <serviceDebug httpHelpPageEnabled="false"/> <serviceMetadata httpGetEnabled="false"/> <serviceTimeouts transactionTimeout="00:10:00"/> <serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/> </behavior> </serviceBehaviors> </behaviors> <!--在tcp中上面幾行和http的配置都是一樣的--> <bindings> <netTcpBinding> <binding name="tcpbinding"> <!--指定為tcp的協議型別--> <security mode="None"> <!--clientCredentialType="None" → 表示加密型別 protectionLevel="None" 表示安全級別--> <transport clientCredentialType="None" protectionLevel="None"/> </security> </binding> </netTcpBinding> </bindings> <services> <service name="MyWCF.WCFSimpleDuplex.Service.CalculatorService" behaviorConfiguration="CalculatorServicebehavior"> <host> <!--這裡配置第一個服務的名稱和服務的具體指向類--> <baseAddresses> <add baseAddress="net.tcp://localhost:9999/CalculatorService"/><!--指定的協議為net tcp協議--> </baseAddresses> </host> <endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding" contract="MyWCF.WCFSimpleDuplex.Interface.ICalculatorService"/> <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> </service> <!--<service name="MyWCF.WCFSimpleDuplex.Service.MathService" behaviorConfiguration="MathServicebehavior"> <host>--><!--這裡配置第二個服務的名稱和服務的具體指向類--><!-- <baseAddresses> <add baseAddress="net.tcp://localhost:9999/MathService"/> </baseAddresses> </host> <endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding" contract="MyWCF.WCFSimpleDuplex.Interface.IMathService"/> <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> </service>--> </services> </system.serviceModel> </configuration>
c) Program程式碼如下:
using System; using System.ServiceModel; using MyWCF.WCFSimpleDuplex.Service; namespace MyWCF.WCFSimpleDuplex.ConsoleTest { class Program { static void Main(string[] args) { try { Console.WriteLine("開始掛起服務"); ServiceInit.Process(); } catch (Exception ex)//如果報無法註冊. . ., 則說明需要管理員許可權, 啟動這個程式 { //服務“SOA.WCF.Service.CalculatorService”有零個應用程式(非基礎結構)終結點。這可能是因為未找到應用程式的配置檔案,或者在配置檔案中未找到與服務名稱匹配的服務元素,或者服務元素中未定義終結點。 //沒有配置檔案 //另一應用程式已使用 HTTP.SYS 註冊了該 URL。 //埠 9999 被其它應用程式佔用了, 找到並將其停止 Console.WriteLine(ex.Message); } Console.Read(); } } /// <summary> /// WCF寄宿到控制檯 /// </summary> public class ServiceInit { public static void Process() { //ServiceHost →表示提供服務的主機,使用服務的型別及其指定的基址初始化 System.ServiceModel.ServiceHost 類的新例項。 Type type = typeof(CalculatorService); ServiceHost host = new ServiceHost(type); host.Opening += (s, e) => Console.WriteLine($"{type} 準備開啟"); //已經開啟事件 host.Opened += (s, e) => Console.WriteLine($"{type} 已經正常開啟"); //開啟服務; 注意當這裡需要Open的時候, 會去配置檔案中檢查是否有配置了MathService這個類的behavior(行為) host.Open(); Console.WriteLine("輸入任何字元,就停止"); Console.Read(); host.Close(); Console.Read(); } } }
8. 完成以上步驟就可以啟動試試看了:
9. 可以使用 cmd 命令 netstat -ano | find "9999", 檢視下埠9999是否被監聽
10. 雙工的服務端已經處理完畢, 接下來開始處理客戶端, 當然客戶端首先就要對剛才的ICallBack進行實現, 這個毋容置疑的
11. 再新開啟一個VS2017, 建立一個控制檯測試專案:
12. 接下來不用多想, 第一件事, 新增服務引用, 第二件事實現服務端的那個ICallBack介面
a) 新增服務引用
b) 實現ICallBack介面, 注意這個類裡的Show 方法, 在客戶端沒有任何程式碼呼叫
using System; namespace MyWCF.WCFSimpleDuplexConsoleTest.CTest { /// <summary> /// 具體實現的回撥 /// </summary> public class CallBackService : MyDuplexConsoleTest.ICalculatorServiceCallback { public void Show(int m, int n, int result) { Console.WriteLine($"回撥操作展示, 這個操作發生在兩秒之後:{m}+{n}={result}"); } } }
c) 整體client截圖:
13. 然後在program中的程式碼, 建議單步除錯看看程式碼的執行過程:
using System; using System.ServiceModel; namespace MyWCF.WCFSimpleDuplexConsoleTest.CTest { class Program { static void Main(string[] args) { MyDuplexConsoleTest.CalculatorServiceClient client = null; try { Console.WriteLine("客戶端來測試雙工!~~"); //建立一個需要回調的例項, 等會服務端進行回撥的 InstanceContext context = new InstanceContext(new CallBackService()); client = new MyDuplexConsoleTest.CalculatorServiceClient(context); client.Plus(123, 234); client.Close(); } catch (Exception ex) { if (client != null) client.Abort(); Console.WriteLine(ex.Message); } Console.Read(); } } }
14. 結果截圖
15. 結束