如何以编程方式修改 WCF app.config 端点地址设置?

Posted

技术标签:

【中文标题】如何以编程方式修改 WCF app.config 端点地址设置?【英文标题】:How to programmatically modify WCF app.config endpoint address setting? 【发布时间】:2010-11-01 06:24:15 【问题描述】:

我想以编程方式修改我的 app.config 文件以设置应使用的服务文件端点。在运行时执行此操作的最佳方法是什么?供参考:

<endpoint address="http://mydomain/MyService.svc"
    binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IASRService"
    contract="ASRService.IASRService" name="WSHttpBinding_IASRService">
    <identity>
        <dns value="localhost" />
    </identity>
</endpoint>

【问题讨论】:

炼金术,您可能需要重新评估您选择的已接受答案 根据我的经验,如果您发现自己需要在运行时修改 app.config,这可能意味着您缺少 .NET 提供的完成您想要做的事情的方法。如果您真正想做的只是点击托管相同服务的不同地址,则亚历克斯·诺特(Alex Knott)在下面的回答指出了这一点。 【参考方案1】:

这是在客户端吗??

如果是这样,您需要创建一个 WsHttpBinding 实例和一个 EndpointAddress,然后将这两个传递给以这两个作为参数的代理客户端构造函数。

// using System.ServiceModel;
WSHttpBinding binding = new WSHttpBinding();
EndpointAddress endpoint = new EndpointAddress(new Uri("http://localhost:9000/MyService"));

MyServiceClient client = new MyServiceClient(binding, endpoint);

如果它位于服务器端,您需要以编程方式创建自己的 ServiceHost 实例,并向其中添加适当的服务端点。

ServiceHost svcHost = new ServiceHost(typeof(MyService), null);

svcHost.AddServiceEndpoint(typeof(IMyService), 
                           new WSHttpBinding(), 
                           "http://localhost:9000/MyService");

当然,您可以将多个这些服务端点添加到您的服务主机。完成后,需要调用 .Open() 方法打开服务主机。

如果您希望能够在运行时动态选择要使用的配置,您可以定义多个配置,每个配置都有一个唯一的名称,然后调用适当的构造函数(用于您的服务主机或代理客户端)使用您希望使用的配置名称。

例如您可以轻松拥有:

<endpoint address="http://mydomain/MyService.svc"
        binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IASRService"
        contract="ASRService.IASRService" 
        name="WSHttpBinding_IASRService">
        <identity>
            <dns value="localhost" />
        </identity>
</endpoint>

<endpoint address="https://mydomain/MyService2.svc"
        binding="wsHttpBinding" bindingConfiguration="SecureHttpBinding_IASRService"
        contract="ASRService.IASRService" 
        name="SecureWSHttpBinding_IASRService">
        <identity>
            <dns value="localhost" />
        </identity>
</endpoint>

<endpoint address="net.tcp://mydomain/MyService3.svc"
        binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IASRService"
        contract="ASRService.IASRService" 
        name="NetTcpBinding_IASRService">
        <identity>
            <dns value="localhost" />
        </identity>
</endpoint>

(三个不同的名称,不同的参数,通过指定不同的 bindingConfigurations)然后选择正确的一个来实例化您的服务器(或客户端代理)。

但在这两种情况下 - 服务器和客户端 - 您必须在实际创建服务主机或代理客户端之前进行选择。 一旦创建,它们就是不可变的 - 一旦它们启动并运行,您就无法对其进行调整。

马克

【讨论】:

如何以编程方式将绑定配置和合同添加到端点? 查看我的答案的顶部 - 您需要创建绑定和端点地址,然后根据这两项创建服务端点(在服务器端)或客户端代理。您不能将绑定“添加”到端点 - 端点由地址 (URI)、绑定和合约三部分组成 这应该是正确的答案,它更详细,更有帮助。 这是一个很好的答案。我只想补充一点,可以在启动代码中更改/更新/修改现有配置的绑定,而无需显式创建主机。类似this.【参考方案2】:

我使用以下代码更改 App.Config 文件中的端点地址。您可能需要在使用前修改或删除命名空间。

using System;
using System.Xml;
using System.Configuration;
using System.Reflection;
//...

namespace Glenlough.Generations.SupervisorII

    public class ConfigSettings
    

        private static string NodePath = "//system.serviceModel//client//endpoint";
        private ConfigSettings()  

        public static string GetEndpointAddress()
        
            return ConfigSettings.loadConfigDocument().SelectSingleNode(NodePath).Attributes["address"].Value;
        

        public static void SaveEndpointAddress(string endpointAddress)
        
            // load config document for current assembly
            XmlDocument doc = loadConfigDocument();

            // retrieve appSettings node
            XmlNode node = doc.SelectSingleNode(NodePath);

            if (node == null)
                throw new InvalidOperationException("Error. Could not find endpoint node in config file.");

            try
            
                // select the 'add' element that contains the key
                //XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[@key='0']", key));
                node.Attributes["address"].Value = endpointAddress;

                doc.Save(getConfigFilePath());
            
            catch( Exception e )
            
                throw e;
            
        

        public static XmlDocument loadConfigDocument()
        
            XmlDocument doc = null;
            try
            
                doc = new XmlDocument();
                doc.Load(getConfigFilePath());
                return doc;
            
            catch (System.IO.FileNotFoundException e)
            
                throw new Exception("No configuration file found.", e);
            
        

        private static string getConfigFilePath()
        
            return Assembly.GetExecutingAssembly().Location + ".config";
        
    

【讨论】:

这有点小技巧,但我还是赞成你,因为我认为这是一个很好的解决方法。 破解与否,当以后使用该程序的用户没有支持时,这可能非常有用 VS2010 .NET 4.0,它是ConfigurationSettings,而不是ConfigSettings 您可以使用:AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 代替 Assembly.GetExecutingAssembly().Location + ".config";【参考方案3】:
SomeServiceClient client = new SomeServiceClient();

var endpointAddress = client.Endpoint.Address; //gets the default endpoint address

EndpointAddressBuilder newEndpointAddress = new EndpointAddressBuilder(endpointAddress);
                newEndpointAddress.Uri = new Uri("net.tcp://serverName:8000/SomeServiceName/");
                client = new SomeServiceClient("EndpointConfigurationName", newEndpointAddress.ToEndpointAddress());

我是这样做的。好消息是它仍然会从配置中获取其余的端点绑定设置,并且只是替换 URI

【讨论】:

您还可以通过跳过手动创建 EndpointAddress 并直接在客户端构造函数中指定地址来进一步简化,例如 var client = new SomeServiceClient("EndpointConfigurationName", "net.tcp://servername :8000/SomeServiceName/")【参考方案4】:

这个短代码对我有用:

Configuration wConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ServiceModelSectionGroup wServiceSection = ServiceModelSectionGroup.GetSectionGroup(wConfig);

ClientSection wClientSection = wServiceSection.Client;
wClientSection.Endpoints[0].Address = <your address>;
wConfig.Save();

当然,您必须在配置更改后创建 ServiceClient 代理。 您还需要引用 System.ConfigurationSystem.ServiceModel 程序集来完成这项工作。

干杯

【讨论】:

这也对我有用。我想修改多个端点,可以创建一个简单的for循环: for (int i = 0; i 这太棒了!我用它来遍历所有端点并在运行时更新 IP 地址,所以我现在有一个用于服务 IP 地址的应用程序设置。【参考方案5】:

这是您可以用来更新应用配置文件的最短代码,即使没有定义配置部分:

void UpdateAppConfig(string param)

   var doc = new XmlDocument();
   doc.Load("YourExeName.exe.config");
   XmlNodeList endpoints = doc.GetElementsByTagName("endpoint");
   foreach (XmlNode item in endpoints)
   
       var adressAttribute = item.Attributes["address"];
       if (!ReferenceEquals(null, adressAttribute))
       
           adressAttribute.Value = string.Format("http://mydomain/0", param);
       
   
   doc.Save("YourExeName.exe.config");

【讨论】:

【参考方案6】:

我已经修改和扩展了 Malcolm Swaine 的代码,以通过其名称属性修改特定节点,并修改外部配置文件。希望对您有所帮助。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;

namespace LobbyGuard.UI.Registration

public class ConfigSettings


    private static string NodePath = "//system.serviceModel//client//endpoint";

    private ConfigSettings()  

    public static string GetEndpointAddress()
    
        return ConfigSettings.loadConfigDocument().SelectSingleNode(NodePath).Attributes["address"].Value;
    

    public static void SaveEndpointAddress(string endpointAddress)
    
        // load config document for current assembly
        XmlDocument doc = loadConfigDocument();

        // retrieve appSettings node
        XmlNodeList nodes = doc.SelectNodes(NodePath);

        foreach (XmlNode node in nodes)
        
            if (node == null)
                throw new InvalidOperationException("Error. Could not find endpoint node in config file.");

            //If this isnt the node I want to change, look at the next one
            //Change this string to the name attribute of the node you want to change
            if (node.Attributes["name"].Value != "DataLocal_Endpoint1")
            
                continue;
            

            try
            
                // select the 'add' element that contains the key
                //XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[@key='0']", key));
                node.Attributes["address"].Value = endpointAddress;

                doc.Save(getConfigFilePath());

                break;
            
            catch (Exception e)
            
                throw e;
            
        
    

    public static void SaveEndpointAddress(string endpointAddress, string ConfigPath, string endpointName)
    
        // load config document for current assembly
        XmlDocument doc = loadConfigDocument(ConfigPath);

        // retrieve appSettings node
        XmlNodeList nodes = doc.SelectNodes(NodePath);

        foreach (XmlNode node in nodes)
        
            if (node == null)
                throw new InvalidOperationException("Error. Could not find endpoint node in config file.");

            //If this isnt the node I want to change, look at the next one
            if (node.Attributes["name"].Value != endpointName)
            
                continue;
            

            try
            
                // select the 'add' element that contains the key
                //XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[@key='0']", key));
                node.Attributes["address"].Value = endpointAddress;

                doc.Save(ConfigPath);

                break;
            
            catch (Exception e)
            
                throw e;
            
        
    

    public static XmlDocument loadConfigDocument()
    
        XmlDocument doc = null;
        try
        
            doc = new XmlDocument();
            doc.Load(getConfigFilePath());
            return doc;
        
        catch (System.IO.FileNotFoundException e)
        
            throw new Exception("No configuration file found.", e);
        
    

    public static XmlDocument loadConfigDocument(string Path)
    
        XmlDocument doc = null;
        try
        
            doc = new XmlDocument();
            doc.Load(Path);
            return doc;
        
        catch (System.IO.FileNotFoundException e)
        
            throw new Exception("No configuration file found.", e);
        
    

    private static string getConfigFilePath()
    
        return Assembly.GetExecutingAssembly().Location + ".config";
    

【讨论】:

太棒了,感谢分享这个并节省了我的时间! :D【参考方案7】:
MyServiceClient client = new MyServiceClient(binding, endpoint);
client.Endpoint.Address = new EndpointAddress("net.tcp://localhost/webSrvHost/service.svc");
client.Endpoint.Binding = new NetTcpBinding()
            
                Name = "yourTcpBindConfig",
                ReaderQuotas = XmlDictionaryReaderQuotas.Max,
                ListenBacklog = 40 

在config中修改uri或在config中绑定信息非常容易。 这是你想要的吗?

【讨论】:

【参考方案8】:

不管怎样,我需要为我的 RESTFul 服务更新 SSL 的端口和方案。这就是我所做的。抱歉,它比原来的问题多一点,但希望对某人有用。

// Don't forget to add references to System.ServiceModel and System.ServiceModel.Web

using System.ServiceModel;
using System.ServiceModel.Configuration;

var port = 1234;
var isSsl = true;
var scheme = isSsl ? "https" : "http";

var currAssembly = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
Configuration config = ConfigurationManager.OpenExeConfiguration(currAssembly);

ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(config);

// Get the first endpoint in services.  This is my RESTful service.
var endp = serviceModel.Services.Services[0].Endpoints[0];

// Assign new values for endpoint
UriBuilder b = new UriBuilder(endp.Address);
b.Port = port;
b.Scheme = scheme;
endp.Address = b.Uri;

// Adjust design time baseaddress endpoint
var baseAddress = serviceModel.Services.Services[0].Host.BaseAddresses[0].BaseAddress;
b = new UriBuilder(baseAddress);
b.Port = port;
b.Scheme = scheme;
serviceModel.Services.Services[0].Host.BaseAddresses[0].BaseAddress = b.Uri.ToString();

// Setup the Transport security
BindingsSection bindings = serviceModel.Bindings;
WebHttpBindingCollectionElement x =(WebHttpBindingCollectionElement)bindings["webHttpBinding"];
WebHttpBindingElement y = (WebHttpBindingElement)x.ConfiguredBindings[0];
var e = y.Security;

e.Mode = isSsl ? WebHttpSecurityMode.Transport : WebHttpSecurityMode.None;
e.Transport.ClientCredentialType = HttpClientCredentialType.None;

// Save changes
config.Save();

【讨论】:

【参考方案9】:

我认为您想要的是在运行时换出配置文件的一个版本,如果是这样,请创建一个具有正确地址的配置文件的副本(也给它提供相关的扩展名,如 .Debug 或 .Release)(它为您提供了一个调试版本和一个运行时版本)并创建一个构建后步骤,该步骤根据构建类型复制正确的文件。

这是我过去使用过的构建后事件的示例,它使用正确的版本(调试/运行时)覆盖输出文件

copy "$(ProjectDir)ServiceReferences.ClientConfig.$(ConfigurationName)" "$(ProjectDir)ServiceReferences.ClientConfig" /Y

在哪里: $(ProjectDir) 是配置文件所在的项目目录 $(ConfigurationName) 是活动的配置构建类型

编辑: 有关如何以编程方式执行此操作的详细说明,请参阅 Marc 的回答。

【讨论】:

您不能使用不在 .config 中的绑定名称。 “测试”将返回错误。这是一个问题,因为通道工厂缓存只有在您指定绑定配置名称而不是绑定对象时才会发生 =(【参考方案10】:

你可以这样做:

将设置保存在单独的 xml 文件中,并在为服务创建代理时通读它。

例如,我想在运行时修改我的服务端点地址,所以我有以下 ServiceEndpoint.xml 文件。

     <?xml version="1.0" encoding="utf-8" ?>
     <Services>
        <Service name="FileTransferService">
           <Endpoints>
              <Endpoint name="ep1" address="http://localhost:8080/FileTransferService.svc" />
           </Endpoints>
        </Service>
     </Services>

用于阅读您的 xml:

 var doc = new XmlDocument();
 doc.Load(FileTransferConstants.Constants.SERVICE_ENDPOINTS_XMLPATH);
 XmlNodeList endPoints = doc.SelectNodes("/Services/Service/Endpoints");  
 foreach (XmlNode endPoint in endPoints)
 
    foreach (XmlNode child in endPoint)
    
        if (child.Attributes["name"].Value.Equals("ep1"))
        
            var adressAttribute = child.Attributes["address"];
            if (!ReferenceEquals(null, adressAttribute))
            
                address = adressAttribute.Value;
            
       
   
  

然后在运行时获取客户端的 web.config 文件并将服务端点地址分配为:

    Configuration wConfig = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap  ExeConfigFilename = @"C:\FileTransferWebsite\web.config" , ConfigurationUserLevel.None);
    ServiceModelSectionGroup wServiceSection = ServiceModelSectionGroup.GetSectionGroup(wConfig);

    ClientSection wClientSection = wServiceSection.Client;
    wClientSection.Endpoints[0].Address = new Uri(address);
    wConfig.Save();

【讨论】:

【参考方案11】:

查看您是否将客户端部分放置在正确的 web.config 文件中。 SharePoint 有大约 6 到 7 个配置文件。 http://msdn.microsoft.com/en-us/library/office/ms460914(v=office.14).aspx (http://msdn.microsoft.com/en-us/library/office/ms460914%28v=office.14%29.aspx)

发这个你可以试试

ServiceClient client = new ServiceClient("ServiceSOAP");

【讨论】:

以上是关于如何以编程方式修改 WCF app.config 端点地址设置?的主要内容,如果未能解决你的问题,请参考以下文章

在调试模式下以编程方式设置 WCF 超时

从.NET调用WCF服务时如何以编程方式添加soap标头?

在 C# 中以编程方式创建 WCF 客户端的标头(wsse)部分

我可以以编程方式控制 WCF 跟踪吗?

如何以编程方式更改端点的身份配置?

如何在生产中配置 WCF 客户端?