积极答复者
关于修改WCFf客户端配置文件的终结点的地址问题

问题
-
由于服务器端的IP地址是变化的,所以需要修改客户端配置文件app.config的<client>节点上<endpoint>的address。
问题一:
我已经在启动客户端后,已有办法修改客户端配置文件app.config中的address,但是修改后,即便是新创建的客户端代理对象,其address依然是修改前的地址,请问有办法刷新没有?我不想重启客户端。
问题二:
如果采用编程的方式来创建客户端代理对象,可以解决IP地址变化的问题,但又有新的问题,因为我想利用配置文件中的绑定设置和身份验证(版主的文章http://www.cnblogs.com/frank_xl/archive/2009/08/12/1543867.html),那么请问用编程方式如何实现身份验证?给个大致的思路就好。
问题三:
关于上面版主文章的身份验证功能,那意味着每调服务器端一个的服务方法都需要验证,是否会降低效率?有更好的验证方式没有?比如.net remoting创建(获取)一个代理对象,验证一次就可以,WCF有没有类似的办法?
答案
-
呵呵,谢谢提醒。
研究了一把,找到解决办法了,针对两种情况各有两种解决办法。
三点:
1. 不要去试图去修改App.config的IP地址,不起作用,除非重启。可以直接在创建代理类对象或是接口时,修改IP地址。至于采用自定义配置文件的方法,我没有去研究,但有哥们用这个方法来完成的,http://blog.csdn.net/shanyou/archive/2008/12/02/4681253.aspx。
2. 针对不用身份验证的
2.1 对于使用代理类:
EndpointAddress address = new EndpointAddress("net.tcp://" + serverAddress + ":8086/UserNamePwdValidatorService");
UserNamePwdValidatorClient userNamePwdValidator
= new UserNamePwdValidatorClient("UserNamePwdValidatorService", address);bool result = userNamePwdValidator.Validate(string.Empty, string.Empty);
2.2 使用工厂类创建:
ChannelFactory<Promotion.WCFContracts.IUserNamePwdValidator> channelFactory
= new ChannelFactory<WCFContracts.IUserNamePwdValidator>("UserNamePwdValidatorService");
EndpointAddress address = new EndpointAddress("net.tcp://" + serverAddress + ":8086/UserNamePwdValidatorService");
Promotion.WCFContracts.IUserNamePwdValidator userNamePwdValidator = channelFactory.CreateChannel(address);bool result = userNamePwdValidator.Validate(string.Empty, string.Empty);
3.使用身份验证
3.1 对于使用代理类:
UserClient user = new UserClient("User");
AddressHeaderCollection headers = new AddressHeaderCollection();
EndpointAddress address = new EndpointAddress(new Uri("net.tcp://" + clientConfig.ServerAddress + ":8086/User"),
user.Endpoint.Address.Identity, headers);
user.Endpoint.Address = address;
user.ClientCredentials.UserName.UserName = username;
user.ClientCredentials.UserName.Password = password;user.Insert();
3.2 使用工厂类创建:
ChannelFactory<Promotion.WCFContracts.UserContracts.IUser> channelFactory
= new ChannelFactory<Promotion.WCFContracts.UserContracts.IUser>("User");
channelFactory.Credentials.UserName.UserName = username;
channelFactory.Credentials.UserName.Password = password;
AddressHeaderCollection headers = new AddressHeaderCollection();
EndpointAddress address = new EndpointAddress(new Uri("net.tcp://" + clientConfig.ServerAddress + ":8086/User"),
channelFactory.Endpoint.Address.Identity, headers);
channelFactory.Endpoint.Address = address;Promotion.WCFContracts.UserContracts.IUser user = channelFactory.CreateChannel();
user.Insert();我写篇博客来做个笔记。
- 已标记为答案 Mog Liang 2010年7月26日 7:02
全部回复
-
1。因为配置文件已经读进内存,所以你的修改只会在程序重新启动后生效。你可以自己使用代码读取配置文件。每次调用都重新读打开读取取一次配置文件。只能这样。
2。凡是配置文件能做的,在WCF里都可以使用代码实现。
3。WCF针对创建的每个Proxy 实例,也是验证一次。这个和Remoting类似。
Frank Xu Lei--谦卑若愚,好学若饥
专注于.NET平台下分布式应用系统开发和企业应用系统集成
Focus on Distributed Applications Development and EAI based on .NET
【老徐的网站】:http://www.frankxulei.com/
【老徐的博客】:http://www.cnblogs.com/frank_xl/
【WCF中文技术论坛】:微软WCF中文技术论坛
【WCF英文技术论坛】:微软WCF英文技术论坛 -
非常谢谢。我查阅了一些英文资料,不重启就没有办法。我彻底死心了,只有用自定义的配置方法了。http://blogs.msdn.com/b/junfeng/archive/2005/02/20/376880.aspx
-
非常谢谢。我查阅了一些英文资料,不重启就没有办法。我彻底死心了,只有用自定义的配置方法了。http://blogs.msdn.com/b/junfeng/archive/2005/02/20/376880.aspx
创建代理客户端的时候,在构造函数中可以传入 url 地址的,其它关于绑定等的设置,代理会自动从配置文件读取.
所以你可以使用编程方式创建代理,并解决IP变化的问题.仔细看自动生成的代理类的构造函数的参数列表.
-
非常谢谢。我查阅了一些英文资料,不重启就没有办法。我彻底死心了,只有用自定义的配置方法了。http://blogs.msdn.com/b/junfeng/archive/2005/02/20/376880.aspx
客气~
Frank Xu Lei--谦卑若愚,好学若饥
专注于.NET平台下分布式应用系统开发和企业应用系统集成
Focus on Distributed Applications Development and EAI based on .NET
【老徐的网站】:http://www.frankxulei.com/
【老徐的博客】:http://www.cnblogs.com/frank_xl/
【WCF中文技术论坛】:微软WCF中文技术论坛
【WCF英文技术论坛】:微软WCF英文技术论坛 -
呵呵,谢谢提醒。
研究了一把,找到解决办法了,针对两种情况各有两种解决办法。
三点:
1. 不要去试图去修改App.config的IP地址,不起作用,除非重启。可以直接在创建代理类对象或是接口时,修改IP地址。至于采用自定义配置文件的方法,我没有去研究,但有哥们用这个方法来完成的,http://blog.csdn.net/shanyou/archive/2008/12/02/4681253.aspx。
2. 针对不用身份验证的
2.1 对于使用代理类:
EndpointAddress address = new EndpointAddress("net.tcp://" + serverAddress + ":8086/UserNamePwdValidatorService");
UserNamePwdValidatorClient userNamePwdValidator
= new UserNamePwdValidatorClient("UserNamePwdValidatorService", address);bool result = userNamePwdValidator.Validate(string.Empty, string.Empty);
2.2 使用工厂类创建:
ChannelFactory<Promotion.WCFContracts.IUserNamePwdValidator> channelFactory
= new ChannelFactory<WCFContracts.IUserNamePwdValidator>("UserNamePwdValidatorService");
EndpointAddress address = new EndpointAddress("net.tcp://" + serverAddress + ":8086/UserNamePwdValidatorService");
Promotion.WCFContracts.IUserNamePwdValidator userNamePwdValidator = channelFactory.CreateChannel(address);bool result = userNamePwdValidator.Validate(string.Empty, string.Empty);
3.使用身份验证
3.1 对于使用代理类:
UserClient user = new UserClient("User");
AddressHeaderCollection headers = new AddressHeaderCollection();
EndpointAddress address = new EndpointAddress(new Uri("net.tcp://" + clientConfig.ServerAddress + ":8086/User"),
user.Endpoint.Address.Identity, headers);
user.Endpoint.Address = address;
user.ClientCredentials.UserName.UserName = username;
user.ClientCredentials.UserName.Password = password;user.Insert();
3.2 使用工厂类创建:
ChannelFactory<Promotion.WCFContracts.UserContracts.IUser> channelFactory
= new ChannelFactory<Promotion.WCFContracts.UserContracts.IUser>("User");
channelFactory.Credentials.UserName.UserName = username;
channelFactory.Credentials.UserName.Password = password;
AddressHeaderCollection headers = new AddressHeaderCollection();
EndpointAddress address = new EndpointAddress(new Uri("net.tcp://" + clientConfig.ServerAddress + ":8086/User"),
channelFactory.Endpoint.Address.Identity, headers);
channelFactory.Endpoint.Address = address;Promotion.WCFContracts.UserContracts.IUser user = channelFactory.CreateChannel();
user.Insert();我写篇博客来做个笔记。
- 已标记为答案 Mog Liang 2010年7月26日 7:02
-
public abstract class WcfClientBase<TChannel> where TChannel : class { private static object _channelLock = new object(); private static ChannelFactory<TChannel> _factory; private static TChannel _channel; private string _endpoint; private string _bindingConfig; public WcfClientBase(string endpoint, string bindingConfig) { _endpoint = endpoint; _bindingConfig = bindingConfig; if (_channel != null) { try { ((IChannel)_channel).Close(TimeSpan.FromMilliseconds(10000)); } catch { ((IChannel)_channel).Abort(); } } if (_factory != null) { try { _factory.Close(TimeSpan.FromMilliseconds(10000)); } catch { _factory.Abort(); } } _channel = null; _factory = null; } public TChannel Channel { get { TChannel localChannel = _channel; if (localChannel == null) { lock (_channelLock) { if (_channel != null) { return _channel; } if (_factory == null) { try { EndpointAddress remoteNodeEndPointAddress = new EndpointAddress(_endpoint); _factory = new ChannelFactory<TChannel>(_bindingConfig, remoteNodeEndPointAddress); } catch { throw; } } _channel = _factory.CreateChannel(); //Note: VERY important to call open here, fix from prior releases where open was not called, //resulting in spotty client-side bottleneck when clients run many threads. ((IChannel)_channel).Open(); return _channel; } } return localChannel; } set { lock (_channelLock) { if (_channel != null && ((IChannel)_channel).State != CommunicationState.Opened) { ((IChannel)_channel).Abort(); _channel = null; if (_factory != null && _factory.State != CommunicationState.Opened) { _factory.Abort(); _factory = null; } } } } } public void Open() { TChannel localChannel = this.Channel; } public void Close() { lock (_channelLock) { if (_channel != null) { try { ((IChannel)_channel).Close(); } catch { ((IChannel)_channel).Abort(); } } if (_factory != null) { try { _factory.Close(); } catch { _factory.Abort(); } } _channel = null; _factory = null; } } }