由於服務器端的IP地址是變化的,所以客戶端在登錄前需要修改連接地址。
思路一:修改客戶端配置文件app.config的<client>節點上<endpoint>的address。
處理方法如下,但是這個方法有個缺點,就是即便修改配置文件中的地址后,即便是新創建的客戶端代理對象,其address依然是修改前的地址,除非重新啟動客戶端。
方法如下:
private void UpdateConfig(string serverIPAddress, string serverPort) { //Configuration config = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location); Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); ConfigurationSectionGroup sct = config.SectionGroups["system.serviceModel"]; ServiceModelSectionGroup serviceModelSectionGroup = sct as ServiceModelSectionGroup; ClientSection clientSection = serviceModelSectionGroup.Client; foreach (ChannelEndpointElement item in clientSection.Endpoints) { string pattern = "://.*/"; string address = item.Address.ToString(); string replacement = string.Format("://{0}:{1}/", serverIPAddress, serverPort); address = Regex.Replace(address, pattern, replacement); item.Address = new Uri(address); } config.Save(ConfigurationSaveMode.Modified); ConfigurationManager.RefreshSection("system.serviceModel"); }
至於是否有辦法可以刷新這個地址,答案是否定的。原因是.Net framework 在客戶端啟動時就將app.config 讀入了,而且后面即便修改了app.config文件,也不會刷新app.config的內容。
至於為什么不重新加載,文章【1】說在通常使用時不可能的。如果要刷新app.config的內容,需要知道app.config的內容何時改變了,這可以通過注冊“文件改變通知”事件來實現。然而一旦檢測到app.config的內容改變,需要通知所有使用了app.config的組件。
那么問題就來了, .Net framework 如何來知道哪些組件使用了app.config,由於注冊機制的缺陷,是不可能做到。進一步說,實現了所有需要讀取app.config的組件在.Net framework中注冊這個機制。當.Net framework檢測到app.config的改變,它將通知每個注冊組件app.config已改變。那么組件該現在該如何做呢?
為了讓app.config新的改變生效,組件不得不重新啟動它自己。這意味着組件需要能夠刷新舊的配置,以及那些基於舊的配置的數據和行為,然后讀取新的配置,並從新的配置開始刷新。
這是不可能的。舉個綁定策略的例子。如果舊的綁定策略認為它需要從裝配件(assembly)A中獲得版本1,而新的策略認為它需要從從裝配件(assembly)A中獲得版本2。在裝配件(assembly)A的版本1已經加載的情況下, .Net framework 無法為新的綁定策略從裝配件(assembly)A中獲得版本2。
僅僅只有一小部分的配置數據可以刷新。這些包括無狀態影響或是影響很容易被消除的配置數據。緩存大小就是一個好的例子。在緩存大小改變上,你能重新設置緩存大小,數據仍然保存着,或者簡單移除舊的緩存並開啟一個新的緩存塊。
通常來說,當app.config發生改變時,確保所有組件一致性的方法是重啟應用程序。這個方法.Net framework所采用的。
ASP.Net有內置的關於app.config發生改變的檢測機制,它在監控web.config上發生的改變。一旦它檢測到改變,它將關閉舊的應用程序重新啟動新的應用程序。
因此,.Net framework將來也不會提供配置數據刷新的特征,如果你認為這個對於你很重要,你必須自己去實現這個。
幸運的是企業庫("Enterprise Library")那幫人理解了這個需求,他們在最新的企業庫版本中開發了個“應用程序配置塊”(Configuration Application Block)。
思路二:如何在不重新啟動客戶端的情況下改變服務器端的地址。總共有兩大類,各有兩種情況。
第一大類:對於使用代理類
兩種情況:
(1)不使用身份驗證
(2)使用身份驗證
/// <summary> /// 調用方案一 /// </summary> /// <param name="serverAddress">服務器地址</param> private static void CallFirstScheme(string serverAddress) { /* /*----------------------方案一:對於使用代理類-----------------------------------------*/ Console.WriteLine("方案一:"); //1.測試連接(不使用身份驗證) Console.WriteLine("1.1.1 創建代理對象 userNamePwdValidator."); EndpointAddress address = new EndpointAddress("net.tcp://" + serverAddress + ":8086/UserNamePwdValidator/UserNamePwdValidatorService"); UserNamePwdValidatorClient userNamePwdValidator = new UserNamePwdValidatorClient("UserNamePwdValidatorService", address); bool result = userNamePwdValidator.Validate(string.Empty, string.Empty); Console.WriteLine("1.1.2 測試連接成功."); //2.驗證用戶名和密碼(與測試連接調用同樣的接口,不使用身份驗證) //bool result = userNamePwdValidator.Validate("admin", admin); //3.調用服務(使用身份驗證) Console.WriteLine("1.2.1 創建服務代理對象 user."); UserClient user = new UserClient("UserService"); user.Endpoint.Address = new EndpointAddress(new Uri("net.tcp://" + serverAddress + ":8086/User"), user.Endpoint.Address.Identity, user.Endpoint.Address.Headers); user.ClientCredentials.UserName.UserName = "admin"; user.ClientCredentials.UserName.Password = "admin"; user.Insert(); Console.WriteLine("1.2.2 調用服務成功./n"); /*----------------------方案一:結束-------------------------------------------------*/ }
第二大類:對於使用工廠類
兩種情況:
(1)不使用身份驗證
(2)使用身份驗證
/// <summary> /// 調用方案二 /// </summary> /// <param name="serverAddress">服務器地址</param> private static void CallSecondScheme(string serverAddress) { /*----------------------方案二:對於使用工廠類-----------------------------------------*/ Console.WriteLine("方案二:"); //1.測試連接(不使用身份驗證) Console.WriteLine("2.1.1 創建接口對象 userNamePwdValidator."); ChannelFactory<WCFContracts.IUserNamePwdValidator> channelFactory = new ChannelFactory<WCFContracts.IUserNamePwdValidator>("Another_UserNamePwdValidatorService"); channelFactory.Endpoint.Address = new EndpointAddress("net.tcp://" + serverAddress + ":8086/UserNamePwdValidator/UserNamePwdValidatorService"); WCFContracts.IUserNamePwdValidator otherUserNamePwdValidator = channelFactory.CreateChannel(); bool result = otherUserNamePwdValidator.Validate(string.Empty, string.Empty); Console.WriteLine("2.1.2 測試連接成功."); //2.驗證用戶名和密碼(與測試連接調用同樣的接口,不使用身份驗證) //bool result = userNamePwdValidator.Validate("admin", admin); //3.調用服務 Console.WriteLine("2.2.1 創建接口對象 user."); ChannelFactory<WCFContracts.IUser> otherChannelFactory = new ChannelFactory<WCFContracts.IUser>("Another_UserService"); otherChannelFactory.Credentials.UserName.UserName = "admin"; otherChannelFactory.Credentials.UserName.Password = "admin"; otherChannelFactory.Endpoint.Address = new EndpointAddress(new Uri("net.tcp://" + serverAddress + ":8086/User"), otherChannelFactory.Endpoint.Address.Identity, otherChannelFactory.Endpoint.Address.Headers); WCFContracts.IUser otherUser = otherChannelFactory.CreateChannel(); otherUser.Insert(); Console.WriteLine("2.2.2 調用服務成功./n"); /*----------------------方案二:結束-------------------------------------------------*/ }
附帶身份驗證:
在VS工具的命令行中:
(1)添加證書:
makecert -sr LocalMachine -ss My -a sha1 -n CN=MyWCFServer -sky exchange -pe
(2)將證書設置成可信任的
certmgr -add -r LocalMachine -s My -c -n MyWCFServer -s TrustedPeople
請自行修改代碼中關於服務器端和客戶端配置文件與證書相關的部分。
http://files.cnblogs.com/scucj/UserNameAndPwdApp.rar
