權限管理系統系列之WCF通訊

目錄html

權限管理系統系列之序言     sql

        首先說下題外話,有些園友看了前一篇【權限管理系統系列之序言】博客加了QQ羣(186841119),看了我寫的權限管理系統的相關文檔(主要是介紹已經開發的功能),給出了一些建議,感受很是好,但願後續有更多的園友能再接再礪給出更多的指導意見,在日常的開發中我的會結合大家的建議作出適當修改和完善,促進共同窗習和進步。關於源碼共享的問題,可能會過段時間公佈,不會如今公開源碼,我的還在不斷完善中,等完成差很少後會公開源碼。數據庫

        客戶端與服務器的通訊在一個程序中會佔住關鍵的做用,處理起來可能會有不少方式,好比說Remoting、Socket、WebServices、WCF等等均可以實現。本人這幾種基本上都用過,Socket可能比較少些,一些聊天室的程序就會使用Socket,經過字節的形式接收數據;WebServices會WinCE開發中使用到,數據傳輸進行壓縮,這樣操做數據就比較方便,實時操做數據庫;Remoting主要用在MIS系統的客戶端與服務端通訊,我的也說不出那種好;WCF也是我最近一兩年才接觸到的,公司如今使用的就是WCF通訊的,我的感受用WCF比較方便和簡單,實用起來使用三個函數(一個函數是檢測客戶端與服務器端的心跳,一個是用於登陸的、一個是公共的接口,基本上全部的客戶端和服務端的通訊都是用這個函數),這個函數能夠搞定全部的客戶端訪問服務端的方法,全部的SQL在服務端執行,便於維護和平常的分工,不過在日常的開發中也不會分客戶端和服務端的開發,基本上也是一個一個模塊進行分工的。json

WCF的配置(包括客戶端和服務端)服務器

客戶端的配置文件:多線程

 1 <?xml version="1.0"?>
 2 <configuration>
 3   <system.serviceModel>
 4     <bindings>
 5       <netTcpBinding>
 6         <binding name="TcpBinding_AppService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="10485760" maxBufferSize="10485760" maxConnections="10" maxReceivedMessageSize="10485760">
 7           <readerQuotas maxDepth="32" maxStringContentLength="10485760" maxArrayLength="10485760" maxBytesPerRead="10485760" maxNameTableCharCount="10485760"/>
 8           <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
 9           <security mode="None">
10             <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
11             <message clientCredentialType="Windows"/>
12           </security>
13         </binding>
14 
15         <binding name="TcpBinding_MessageService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="10485760" maxBufferSize="10485760" maxConnections="10" maxReceivedMessageSize="10485760">
16           <readerQuotas maxDepth="32" maxStringContentLength="10485760" maxArrayLength="10485760" maxBytesPerRead="10485760" maxNameTableCharCount="10485760"/>
17           <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
18           <security mode="None">
19             <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
20             <message clientCredentialType="Windows"/>
21           </security>
22         </binding>
23 
24       </netTcpBinding>
25     </bindings>
26     <client>
27       <endpoint address="net.tcp://localhost:9090/AppService" binding="netTcpBinding" bindingConfiguration="TcpBinding_AppService" contract="IAppService" name="TcpBinding_AppService"/>
28 
29       <endpoint address="net.tcp://localhost:7070/MessageService" binding="netTcpBinding" bindingConfiguration="TcpBinding_MessageService" contract="IMessageService" name="TcpBinding_MessageService"/>
30     </client>
31   </system.serviceModel>
32 </configuration>
View Code

服務端的配置文件:併發

 

 1 <?xml version="1.0"?>
 2 <configuration>
 3   <system.serviceModel>
 4     <services>
 5       <service behaviorConfiguration="Service.Behavior" name="Server.AppService">
 6         <endpoint address="AppService" binding="netTcpBinding" bindingConfiguration="AppServiceBinding" name="TcpBinding_AppService" contract="Server.IAppService" />
 7         <endpoint address="AppService/mex" binding="mexTcpBinding" contract="IMetadataExchange" />
 8         <host>
 9           <baseAddresses>
10             <add baseAddress="net.tcp://localhost:9090" />
11           </baseAddresses>
12         </host>
13       </service>
14       <service behaviorConfiguration="Service.Behavior" name="Server.MessageService">
15         <endpoint address="MessageService" binding="netTcpBinding" bindingConfiguration="MessageServiceBinding" name="TcpBinding_MessageService" contract="Server.IMessageService" />
16         <endpoint address="MessageService/mex" binding="mexTcpBinding" contract="IMetadataExchange" />
17         <host>
18           <baseAddresses>
19             <add baseAddress="net.tcp://localhost:7070" />
20           </baseAddresses>
21         </host>
22       </service>
23     </services>
24     <bindings>
25       <netTcpBinding>
26         <binding name="AppServiceBinding" maxBufferSize="10485760" maxReceivedMessageSize="10485760">
27           <readerQuotas maxDepth="32" maxStringContentLength="10485760"
28  maxArrayLength="10485760" maxBytesPerRead="10485760" maxNameTableCharCount="10485760" />
29           <reliableSession ordered="true" inactivityTimeout="00:10:00"
30  enabled="false" />
31           <security mode="None" />
32         </binding>
33         <binding name="MessageServiceBinding" maxBufferSize="10485760" maxReceivedMessageSize="10485760">
34           <readerQuotas maxDepth="32" maxStringContentLength="10485760"
35  maxArrayLength="10485760" maxBytesPerRead="10485760" maxNameTableCharCount="10485760" />
36           <reliableSession ordered="true" inactivityTimeout="00:10:00"
37  enabled="false" />
38           <security mode="None" />
39         </binding>
40       </netTcpBinding>
41     </bindings>
42     <behaviors>
43       <serviceBehaviors>
44         <behavior name="Service.Behavior">
45           <serviceMetadata />
46           <serviceDebug includeExceptionDetailInFaults="true" />
47           <!--會話最大數量(併發會話)-->
48           <serviceThrottling maxConcurrentSessions="100" />
49           <!--數據序列最大量-->
50           <dataContractSerializer maxItemsInObjectGraph="10485760" />
51         </behavior>
52         <behavior name="mexConfig">
53           <serviceDebug includeExceptionDetailInFaults="True" />
54           <serviceMetadata />
55         </behavior>
56       </serviceBehaviors>
57     </behaviors>
58   </system.serviceModel>
59 </configuration>
View Code

 

以上爲客戶端與服務端的配置文件,有兩個配置,一個爲基本通訊所用,一個爲雙工通訊所用。tcp

 

介紹完配置文件後再介紹實現函數:ide

 

 1 [ServiceContract(Name = "IAppService", SessionMode = SessionMode.Allowed, Namespace = "http://tempuri.org/")]
 2     public interface IAppService
 3     {
 4         //心跳
 5         [OperationContract]
 6         string HeartBeat(string echo);
 7 
 8         //登陸
 9         [OperationContract]
10         bool Login(string UserName, string Password);
11 
12         //統一的應用業務請求調用,用於會話控制和調用轉發
13         [OperationContract]
14         Result AppCall(Request request);
15     }
16 
17     #region * 推送消息
18     [ServiceContract(CallbackContract = typeof(IPushClient))]
19     public interface IMessageService
20     {
21         [OperationContract]
22         void RegisterClient();
23     }
24 
25     public interface IPushClient
26     {
27         [OperationContract(IsOneWay = true)]
28         void SendMessage(string message);
29     }
30     #endregion

 

      分別有三個函數,一個是維持服務端與客戶端的心跳,一個爲登錄所用,一個爲全部函數的接口,基本上全部的通訊都是經過這個函數進行調用。最下面的爲雙工通訊的定義,定義成回調函數的形式。函數

以上函數實現邏輯:

  1  //每一個會話一個實例,同一個會話下的多線程併發
  2     [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
  3     public class AppService : IAppService
  4     {
  5         //記錄是否登陸
  6         bool IsLogined = false;
  7         Context context = new Context();
  8 
  9         private static readonly string _username = "Server";
 10         private static readonly string _password = "123456";
 11 
 12         //心跳請求,維持鏈路正常
 13         public string HeartBeat(string echo)
 14         {
 15             Log.Log.Debug("收到請求:" + echo);
 16             return "Re:" + echo;
 17         }
 18 
 19         //用於登陸
 20         public bool Login(string UserName, string Password)
 21         {
 22             Log.Log.Debug("收到請求:" + UserName + ";" + Password);
 23             if (_username.Equals(Encrypt.DecryptDES(UserName, Const.EncryptKey)) && _password.Equals(Encrypt.DecryptDES(Password, Const.EncryptKey)))
 24             {
 25                 IsLogined = true;
 26                 context.UserName = UserName;
 27                 return IsLogined;
 28             }
 29             else
 30             {
 31                 IsLogined = false;
 32                 context.UserName = "";
 33                 return IsLogined;
 34             }
 35         }
 36 
 37         //統一的業務請求調用代理
 38         delegate Result ActionDelegate(string reqdata);
 39         //統一的應用業務請求調用,用於會話控制和調用轉發
 40         public Result AppCall(Request request)
 41         {
 42             if (!string.IsNullOrEmpty(request.data))
 43             {
 44                 if (request.data.Contains(JSON.CompressionFlag))
 45                 {
 46                     Log.Log.Debug("收到請求:" + Compression.DecompressString(request.data.Replace(JSON.CompressionFlag, JSON.ReplaceFlag)));
 47                 }
 48                 else
 49                 {
 50                     Log.Log.Debug("收到請求:" + request.data);
 51                 }
 52             }
 53             if (!IsLogined)
 54             {
 55                 Result result = new Result() { success = false, errors = "用戶未登陸,請登陸後再提交請求!" };
 56                 Log.Log.Info("Server.AppService.AppCall(Request request):" + JSON.Object2Json(result, false));
 57                 return result;
 58             }
 59 
 60             if (request.action == null || request.method == null)
 61             {
 62                 Result result = new Result() { success = false, errors = "請求數據格式不正確{request.action==null || request.method==null},請檢查!" };
 63                 Log.Log.Error("Server.AppService.AppCall(Request request)出錯:" + JSON.Object2Json(result, false));
 64                 return result;
 65 
 66             }
 67             try
 68             {
 69                 Type type = Type.GetType("Server.Action." + request.action);
 70                 object action = Activator.CreateInstance(type, new object[] { this.context });
 71                 ActionDelegate doAction = (ActionDelegate)Delegate.CreateDelegate(typeof(ActionDelegate), action, request.method);
 72                 Result result = doAction(request.data);
 73                 return result;
 74             }
 75             catch (Exception e)
 76             {
 77                 Log.Log.Error("Server.AppService.AppCall(Request request)異常:" + e.ToString());
 78                 return new Result() { success = false, errors = "執行業務請求錯誤!" };
 79             }
 80         }
 81     }
 82 
 83     #region * 推送消息
 84     [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
 85     public class MessageService : IMessageService, IDisposable
 86     {
 87         public static List<IPushClient> ClientCallbackList { get; set; }
 88         public MessageService()
 89         {
 90             ClientCallbackList = new List<IPushClient>();
 91         }
 92 
 93         public void RegisterClient()
 94         {
 95             var client = OperationContext.Current.GetCallbackChannel<IPushClient>();
 96             var id = OperationContext.Current.SessionId;
 97             //Console.WriteLine("{0}registered.", id);
 98             Log.Log.Info(string.Format("{0}registered.", id));
 99             OperationContext.Current.Channel.Closing+=new EventHandler(Channel_Closing);
100             ClientCallbackList.Add(client);
101         }
102 
103         private void Channel_Closing(object sender, EventArgs e)
104         {
105             lock (ClientCallbackList)
106             {
107                 ClientCallbackList.Remove((IPushClient)sender);
108             }
109         }
110 
111         public void Dispose()
112         {
113             ClientCallbackList.Clear();
114         }
115     }
116     #endregion
117 }
View Code

 

       通訊接口經過以上實體,success爲函數執行狀態,msg爲函數返回的信息,data爲返回的數據(格式爲json格式的),errors爲返回的錯誤信息,sql爲函數執行的sql,返回給前臺界面。

WCF服務生成客戶端的配置文件步驟:
a.打開vs命令行,用cd進入到exe文件目錄。
b.svcutil .exe
c.svcutil *.wsdl *.xsd
完成以上便可。

客戶調用CS文件:

  1 //------------------------------------------------------------------------------
  2 // <auto-generated>
  3 //     此代碼由工具生成。
  4 //     運行時版本:4.0.30319.18444
  5 //
  6 //     對此文件的更改可能會致使不正確的行爲,而且若是
  7 //     從新生成代碼,這些更改將會丟失。
  8 // </auto-generated>
  9 //------------------------------------------------------------------------------
 10 
 11 namespace Server.Domain
 12 {
 13     using System.Runtime.Serialization;
 14 
 15 
 16     [System.Diagnostics.DebuggerStepThroughAttribute()]
 17     [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
 18     [System.Runtime.Serialization.DataContractAttribute(Name = "Request", Namespace = "http://schemas.datacontract.org/2004/07/Server.Domain")]
 19     public partial class Request : object, System.Runtime.Serialization.IExtensibleDataObject
 20     {
 21 
 22         private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
 23 
 24         private string actionField;
 25 
 26         private string dataField;
 27 
 28         private string methodField;
 29 
 30         public System.Runtime.Serialization.ExtensionDataObject ExtensionData
 31         {
 32             get
 33             {
 34                 return this.extensionDataField;
 35             }
 36             set
 37             {
 38                 this.extensionDataField = value;
 39             }
 40         }
 41 
 42         [System.Runtime.Serialization.DataMemberAttribute()]
 43         public string action
 44         {
 45             get
 46             {
 47                 return this.actionField;
 48             }
 49             set
 50             {
 51                 this.actionField = value;
 52             }
 53         }
 54 
 55         [System.Runtime.Serialization.DataMemberAttribute()]
 56         public string data
 57         {
 58             get
 59             {
 60                 return this.dataField;
 61             }
 62             set
 63             {
 64                 this.dataField = value;
 65             }
 66         }
 67 
 68         [System.Runtime.Serialization.DataMemberAttribute()]
 69         public string method
 70         {
 71             get
 72             {
 73                 return this.methodField;
 74             }
 75             set
 76             {
 77                 this.methodField = value;
 78             }
 79         }
 80     }
 81 
 82     [System.Diagnostics.DebuggerStepThroughAttribute()]
 83     [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
 84     [System.Runtime.Serialization.DataContractAttribute(Name = "Result", Namespace = "http://schemas.datacontract.org/2004/07/Server.Domain")]
 85     public partial class Result : object, System.Runtime.Serialization.IExtensibleDataObject
 86     {
 87 
 88         private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
 89 
 90         private string dataField;
 91 
 92         private string errorsField;
 93 
 94         private string msgField;
 95 
 96         private string sqlField;
 97 
 98         private bool successField;
 99 
100         public System.Runtime.Serialization.ExtensionDataObject ExtensionData
101         {
102             get
103             {
104                 return this.extensionDataField;
105             }
106             set
107             {
108                 this.extensionDataField = value;
109             }
110         }
111 
112         [System.Runtime.Serialization.DataMemberAttribute()]
113         public string data
114         {
115             get
116             {
117                 return this.dataField;
118             }
119             set
120             {
121                 this.dataField = value;
122             }
123         }
124 
125         [System.Runtime.Serialization.DataMemberAttribute()]
126         public string errors
127         {
128             get
129             {
130                 return this.errorsField;
131             }
132             set
133             {
134                 this.errorsField = value;
135             }
136         }
137 
138         [System.Runtime.Serialization.DataMemberAttribute()]
139         public string msg
140         {
141             get
142             {
143                 return this.msgField;
144             }
145             set
146             {
147                 this.msgField = value;
148             }
149         }
150 
151         [System.Runtime.Serialization.DataMemberAttribute()]
152         public string sql
153         {
154             get
155             {
156                 return this.sqlField;
157             }
158             set
159             {
160                 this.sqlField = value;
161             }
162         }
163 
164         [System.Runtime.Serialization.DataMemberAttribute()]
165         public bool success
166         {
167             get
168             {
169                 return this.successField;
170             }
171             set
172             {
173                 this.successField = value;
174             }
175         }
176     }
177 }
178 
179 
180 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
181 [System.ServiceModel.ServiceContractAttribute(ConfigurationName = "IAppService")]
182 public interface IAppService
183 {
184 
185     [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IAppService/HeartBeat", ReplyAction = "http://tempuri.org/IAppService/HeartBeatResponse")]
186     string HeartBeat(string echo);
187 
188     [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IAppService/Login", ReplyAction = "http://tempuri.org/IAppService/LoginResponse")]
189     bool Login(string UserName, string Password);
190 
191     [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IAppService/AppCall", ReplyAction = "http://tempuri.org/IAppService/AppCallResponse")]
192     Server.Domain.Result AppCall(Server.Domain.Request request);
193 }
194 
195 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
196 public interface IAppServiceChannel : IAppService, System.ServiceModel.IClientChannel
197 {
198 }
199 
200 [System.Diagnostics.DebuggerStepThroughAttribute()]
201 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
202 public partial class AppServiceClient : System.ServiceModel.ClientBase<IAppService>, IAppService
203 {
204 
205     public AppServiceClient()
206     {
207     }
208 
209     public AppServiceClient(string endpointConfigurationName) :
210         base(endpointConfigurationName)
211     {
212     }
213 
214     public AppServiceClient(string endpointConfigurationName, string remoteAddress) :
215         base(endpointConfigurationName, remoteAddress)
216     {
217     }
218 
219     public AppServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
220         base(endpointConfigurationName, remoteAddress)
221     {
222     }
223 
224     public AppServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
225         base(binding, remoteAddress)
226     {
227     }
228 
229     public string HeartBeat(string echo)
230     {
231         return base.Channel.HeartBeat(echo);
232     }
233 
234     public bool Login(string UserName, string Password)
235     {
236         return base.Channel.Login(UserName, Password);
237     }
238 
239     public Server.Domain.Result AppCall(Server.Domain.Request request)
240     {
241         return base.Channel.AppCall(request);
242     }
243 }
244 
245 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
246 [System.ServiceModel.ServiceContractAttribute(ConfigurationName = "IMessageService", CallbackContract = typeof(IMessageServiceCallback))]
247 public interface IMessageService
248 {
249 
250     [System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IMessageService/RegisterClient", ReplyAction = "http://tempuri.org/IMessageService/RegisterClientResponse")]
251     void RegisterClient();
252 }
253 
254 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
255 public interface IMessageServiceCallback
256 {
257 
258     [System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "http://tempuri.org/IMessageService/SendMessage")]
259     void SendMessage(string message);
260 }
261 
262 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
263 public interface IMessageServiceChannel : IMessageService, System.ServiceModel.IClientChannel
264 {
265 }
266 
267 [System.Diagnostics.DebuggerStepThroughAttribute()]
268 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
269 public partial class MessageServiceClient : System.ServiceModel.DuplexClientBase<IMessageService>, IMessageService
270 {
271 
272     public MessageServiceClient(System.ServiceModel.InstanceContext callbackInstance) :
273         base(callbackInstance)
274     {
275     }
276 
277     public MessageServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName) :
278         base(callbackInstance, endpointConfigurationName)
279     {
280     }
281 
282     public MessageServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress) :
283         base(callbackInstance, endpointConfigurationName, remoteAddress)
284     {
285     }
286 
287     public MessageServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
288         base(callbackInstance, endpointConfigurationName, remoteAddress)
289     {
290     }
291 
292     public MessageServiceClient(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
293         base(callbackInstance, binding, remoteAddress)
294     {
295     }
296 
297     public void RegisterClient()
298     {
299         base.Channel.RegisterClient();
300     }
301 }
View Code
 1        public static AppServiceClient AppService;
 2         public static ServiceHearBeat HeartBeat;
 3         /// <summary>
 4         /// 鏈接是否正常
 5         /// </summary>
 6         public static bool IsAlive
 7         {
 8             get { return HeartBeat.IsAlive; }
 9         }
10         /// <summary>
11         /// 是否已經彈出過提示
12         /// </summary>
13         public static bool HasNotice
14         {
15             get { return HeartBeat.HasNotice; }
16             set { HeartBeat.HasNotice = value; }
17         }
18 
19 
20          //鏈接到應用服務
21           if (!ConnectToAppServer())
22           {
23                 Comm.MessageBox.Info("鏈接服務端失敗,請檢查服務端是否已經啓動。");
24                  return;
25            }
26 
27 //鏈接到應用服務
28         public static bool ConnectToAppServer()
29         {
30             try
31             {
32                 //若是服務存在,則嘗試關閉連接
33                 if (AppService != null)
34                 {
35                     try
36                     {
37                         AppService.Close();
38                     }
39                     catch (Exception)
40                     {
41                     }
42                 }
43                 //建立新的服務對象,並進行鏈接和登陸
44                 AppService = new AppServiceClient();
45                 AppService.Open();
46                 if (!AppClient.AppService.Login(Encrypt.EncryptDES("Server", Const.EncryptKey), Encrypt.EncryptDES("123456", Const.EncryptKey)))
47                 {
48                     return false;
49                 }
50                 return true;
51             }
52             catch (EndpointNotFoundException)
53             {
54                 Log.Error("鏈接服務端失敗,服務端IP端口配置錯誤或者是服務端還沒有啓動");
55             }
56             catch (SocketException)
57             {
58                 Log.Error("鏈接服務端失敗,服務端IP端口配置錯誤或者是服務端還沒有啓動");
59             }
60             catch (Exception e)
61             {
62                 Log.Error("鏈接服務端出錯:" + e.ToString());
63             }
64             return false;
65 
66         }
View Code

以上便可完成對客戶端鏈接服務端了,基本上完成之後步驟能夠說完成了WCF的通訊,實現了客戶端鏈接服務端。

服務端打開的效果:

客戶端打開的效果:

如對權限管理系統有興趣可加QQ羣:186841119,可參與相關話題討論。相互學習交流,共同進步。

相關文章
相關標籤/搜索