由于服务器端的IP地址是变化的所以客户端在登录前需要修改连接地址 思路一修改客户端配置文件nfig的<client>节点上<endpoint>的address 处理方法如下但是这个方法有个缺点就是即便修改配置文件中的地址后即便是新创建的客户端代理对象其address依然是修改前的地址除非重新启动客户端 方法如下 private void UpdateConfig(string serverIPAddress string serverPort) { //Configuration config = ConfigurationManagerOpenExeConfiguration(AssemblyGetEntryAssembly()Location); Configuration config = ConfigurationManagerOpenExeConfiguration(ConfigurationUserLevelNone); ConfigurationSectionGroup sct = configSectionGroups[systemserviceModel]; ServiceModelSectionGroup serviceModelSectionGroup = sct as ServiceModelSectionGroup; ClientSection clientSection = serviceModelSectionGroupClient; foreach (ChannelEndpointElement item in clientSectionEndpoints) { string pattern = ://*/; string address = itemAddressToString(); string replacement = stringFormat(://{}:{}/ serverIPAddress serverPort); address = RegexReplace(address pattern replacement); itemAddress = new Uri(address); } configSave(ConfigurationSaveModeModified); ConfigurationManagerRefreshSection(systemserviceModel); } 至于是否有办法可以刷新这个地址答案是否定的原因是Net framework 在客户端启动时就将nfig 读入了而且后面即便修改了nfig文件也不会刷新nfig的内容 至于为什么不重新加载文章【】说在通常使用时不可能的如果要刷新nfig的内容需要知道nfig的内容何时改变了这可以通过注册文件改变通知事件来实现然而一旦检测到nfig的内容改变需要通知所有使用了nfig的组件 那么问题就来了 Net framework 如何来知道哪些组件使用了nfig由于注册机制的缺陷是不可能做到进一步说实现了所有需要读取nfig的组件在Net framework中注册这个机制当Net framework检测到nfig的改变它将通知每个注册组件nfig已改变那么组件该现在该如何做呢? 为了让nfig新的改变生效组件不得不重新启动它自己这意味着组件需要能够刷新旧的配置以及那些基于旧的配置的数据和行为然后读取新的配置并从新的配置开始刷新 这是不可能的举个绑定策略的例子如果旧的绑定策略认为它需要从装配件(assembly)A中获得版本而新的策略认为它需要从从装配件(assembly)A中获得版本在装配件(assembly)A的版本已经加载的情况下 Net framework 无法为新的绑定策略从装配件(assembly)A中获得版本 仅仅只有一小部分的配置数据可以刷新这些包括无状态影响或是影响很容易被消除的配置数据缓存大小就是一个好的例子在缓存大小改变上你能重新设置缓存大小数据仍然保存着或者简单移除旧的缓存并开启一个新的缓存块 通常来说当nfig发生改变时确保所有组件一致性的方法是重启应用程序这个方法Net framework所采用的 ASPNet有内置的关于nfig发生改变的检测机制它在监控nfig上发生的改变一旦它检测到改变它将关闭旧的应用程序重新启动新的应用程序 因此Net framework将来也不会提供配置数据刷新的特征如果你认为这个对于你很重要你必须自己去实现这个 幸运的是企业库(Enterprise Library)那帮人理解了这个需求他们在最新的企业库版本中开发了个应用程序配置块(Configuration Application Block) 思路二如何在不重新启动客户端的情况下改变服务器端的地址总共有两大类各有两种情况 第一大类对于使用代理类 两种情况 ()不使用身份验证 ()使用身份验证 /// <summary> /// 调用方案一 /// </summary> /// <param name=serverAddress>服务器地址</param> private static void CallFirstScheme(string serverAddress) { /* /*方案一对于使用代理类*/ ConsoleWriteLine(方案一); //测试连接(不使用身份验证) ConsoleWriteLine( 创建代理对象 userNamePwdValidator); EndpointAddress address = new EndpointAddress(nettcp:// + serverAddress + :/UserNamePwdValidator/UserNamePwdValidatorService); UserNamePwdValidatorClient userNamePwdValidator = new UserNamePwdValidatorClient(UserNamePwdValidatorService address); bool result = userNamePwdValidatorValidate(stringEmpty stringEmpty); ConsoleWriteLine( 测试连接成功); //验证用户名和密码(与测试连接调用同样的接口不使用身份验证) //bool result = userNamePwdValidatorValidate(admin admin); //调用服务(使用身份验证) ConsoleWriteLine( 创建服务代理对象 user); UserClient user = new UserClient(UserService); userEndpointAddress = new EndpointAddress(new Uri(nettcp:// + serverAddress + :/User) userEndpointAddressIdentity userEndpointAddressHeaders); userClientCredentialsUserNameUserName = admin; userClientCredentialsUserNamePassword = admin; userInsert(); ConsoleWriteLine( 调用服务成功/n); /*方案一结束*/ } 第二大类对于使用工厂类 两种情况 ()不使用身份验证 ()使用身份验证 /// <summary> /// 调用方案二 /// </summary> /// <param name=serverAddress>服务器地址</param> private static void CallSecondScheme(string serverAddress) { /*方案二对于使用工厂类*/ ConsoleWriteLine(方案二); //测试连接(不使用身份验证) ConsoleWriteLine( 创建接口对象 userNamePwdValidator); ChannelFactory<WCFContractsIUserNamePwdValidator> channelFactory = new ChannelFactory<WCFContractsIUserNamePwdValidator>(Another_UserNamePwdValidatorService); channelFactoryEndpointAddress = new EndpointAddress(nettcp:// + serverAddress + :/UserNamePwdValidator/UserNamePwdValidatorService); WCFContractsIUserNamePwdValidator otherUserNamePwdValidator = channelFactoryCreateChannel(); bool result = otherUserNamePwdValidatorValidate(stringEmpty stringEmpty); ConsoleWriteLine( 测试连接成功); //验证用户名和密码(与测试连接调用同样的接口不使用身份验证) //bool result = userNamePwdValidatorValidate(admin admin); //调用服务 ConsoleWriteLine( 创建接口对象 user); ChannelFactory<WCFContractsIUser> otherChannelFactory = new ChannelFactory<WCFContractsIUser>(Another_UserService); otherChannelFactoryCredentialsUserNameUserName = admin; otherChannelFactoryCredentialsUserNamePassword = admin; otherChannelFactoryEndpointAddress = new EndpointAddress(new Uri(nettcp:// + serverAddress + :/User) otherChannelFactoryEndpointAddressIdentity otherChannelFactoryEndpointAddressHeaders); WCFContractsIUser otherUser = otherChannelFactoryCreateChannel(); otherUserInsert(); ConsoleWriteLine( 调用服务成功/n); /*方案二结束*/ } 附带身份验证 在VS工具的命令行中 ()添加证书 makecert sr LocalMachine ss My a sha n CN=MyWCFServer sky exchange pe ()将证书设置成可信任的 certmgr add r LocalMachine s My c n MyWCFServer s TrustedPeople |