none
关于修改WCFf客户端配置文件的终结点的地址问题 RRS feed

  • 问题

  • 由于服务器端的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有没有类似的办法?

     

    2010年7月16日 3:50

答案

  • 呵呵,谢谢提醒。

    研究了一把,找到解决办法了,针对两种情况各有两种解决办法。

    三点:

    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
    2010年7月16日 13:43

全部回复

  • 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英文技术论坛

    2010年7月16日 6:41
    版主
  • 非常谢谢。我查阅了一些英文资料,不重启就没有办法。我彻底死心了,只有用自定义的配置方法了。http://blogs.msdn.com/b/junfeng/archive/2005/02/20/376880.aspx

    2010年7月16日 8:09
  • 非常谢谢。我查阅了一些英文资料,不重启就没有办法。我彻底死心了,只有用自定义的配置方法了。http://blogs.msdn.com/b/junfeng/archive/2005/02/20/376880.aspx

    创建代理客户端的时候,在构造函数中可以传入 url 地址的,其它关于绑定等的设置,代理会自动从配置文件读取.

    所以你可以使用编程方式创建代理,并解决IP变化的问题.仔细看自动生成的代理类的构造函数的参数列表.

     

     

    2010年7月16日 8:13
  • 非常谢谢。我查阅了一些英文资料,不重启就没有办法。我彻底死心了,只有用自定义的配置方法了。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英文技术论坛

    2010年7月16日 8:17
    版主
  • 呵呵,谢谢提醒。

    研究了一把,找到解决办法了,针对两种情况各有两种解决办法。

    三点:

    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
    2010年7月16日 13:43
  • 你这个不完整,回头我给你个更简单的,只改 url,其它全在配置里。
    2010年7月16日 14:13
  • 好啊,我花了一晚上写一个解决方案来解决这个问题。如果你有更简单的办法,更好。请有空发出来学习学习。谢了。
    2010年7月16日 17:04
  •   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;
          }
        }
      }
    
    2010年7月19日 1:22