简体   繁体   English

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

[英]How to programmatically modify WCF app.config endpoint address setting?

I'd like to programmatically modify my app.config file to set which service file endpoint should be used.我想以编程方式修改我的 app.config 文件以设置应该使用哪个服务文件端点。 What is the best way to do this at runtime?在运行时执行此操作的最佳方法是什么? For reference:以供参考:

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

Is this on the client side of things??这是在客户端吗?

If so, you need to create an instance of WsHttpBinding, and an EndpointAddress, and then pass those two to the proxy client constructor that takes these two as parameters.如果是这样,您需要创建一个 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);

If it's on the server side of things, you'll need to programmatically create your own instance of ServiceHost, and add the appropriate service endpoints to it.如果它在服务器端,您需要以编程方式创建自己的 ServiceHost 实例,并向其添加适当的服务端点。

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

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

Of course you can have multiple of those service endpoints added to your service host.当然,您可以将多个服务端点添加到您的服务主机。 Once you're done, you need to open the service host by calling the .Open() method.完成后,您需要通过调用 .Open() 方法打开服务主机。

If you want to be able to dynamically - at runtime - pick which configuration to use, you could define multiple configurations, each with a unique name, and then call the appropriate constructor (for your service host, or your proxy client) with the configuration name you wish to use.如果您希望能够在运行时动态选择要使用的配置,您可以定义多个配置,每个配置都有一个唯一的名称,然后使用配置调用适当的构造函数(对于您的服务主机或代理客户端)您希望使用的名称。

Eg you could easily have:例如,您可以轻松拥有:

<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>

(three different names, different parameters by specifying different bindingConfigurations) and then just pick the right one to instantiate your server (or client proxy). (三个不同的名称,通过指定不同的 bindingConfigurations 不同的参数)然后选择正确的一个来实例化您的服务器(或客户端代理)。

But in both cases - server and client - you have to pick before actually creating the service host or the proxy client.但在这两种情况下 - 服务器和客户端 - 您必须在实际创建服务主机或代理客户端之前进行选择。 Once created, these are immutable - you cannot tweak them once they're up and running.一旦创建,这些是不可变的- 一旦它们启动并运行,您就无法调整它们。

Marc马克

I use the following code to change the endpoint address in the App.Config file.我使用以下代码更改 App.Config 文件中的端点地址。 You may want to modify or remove the namespace before usage.您可能希望在使用前修改或删除命名空间。

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";
        }
    }
}
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());

I did it like this.我是这样做的。 The good thing is it still picks up the rest of your endpoint binding settings from the config and just replaces the URI .好消息是它仍然从配置中获取其余的端点绑定设置,只是替换 URI

this short code worked for me:这个简短的代码对我有用:

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

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

Of course you have to create the ServiceClient proxy AFTER the config has changed.当然,您必须在配置更改后创建 ServiceClient 代理。 You also need to reference the System.Configuration and System.ServiceModel assemblies to make this work.您还需要引用System.ConfigurationSystem.ServiceModel程序集来完成这项工作。

Cheers干杯

I have modified and extended Malcolm Swaine's code to modify a specific node by it's name attribute, and to also modify an external config file.我已经修改并扩展了 Malcolm Swaine 的代码,以通过其名称属性修改特定节点,并修改外部配置文件。 Hope it helps.希望能帮助到你。

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";
    }
}

} }

This is the shortest code that you can use to update the app config file even if don't have a config section defined:即使没有定义配置部分,这是您可以用来更新应用程序配置文件的最短代码:

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");
}
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 }

It's very easy to modify the uri in config or binding info in config.修改 config 中的 uri 或 config 中的绑定信息非常容易。 Is this what you want?这是你想要的吗?

For what it's worth, I needed to update the port and scheme for SSL for my RESTFul service.无论如何,我需要为我的 RESTFul 服务更新 SSL 的端口和方案。 This is what I did.这就是我所做的。 Apologies that it is a bit more that the original question, but hopefully useful to someone.抱歉,这比原始问题要多一些,但希望对某人有用。

// 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();

You can do it like this:你可以这样做:

  • Keep your settings in a separate xml file and read through it when you create a proxy for your service.将您的设置保存在单独的 xml 文件中,并在为您的服务创建代理时通读它。

For example , i want to modify my service endpoint address at runtime so i have the following ServiceEndpoint.xml file.例如,我想在运行时修改我的服务端点地址,所以我有以下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>
  • For reading your xml :阅读您的 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; } } } }
  • Then get your web.config file of your client at runtime and assign the service endpoint address as:然后在运行时获取客户端的 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();

I think what you want is to swap out at runtime a version of your config file, if so create a copy of your config file (also give it the relevant extension like .Debug or .Release) that has the correct addresses (which gives you a debug version and a runtime version ) and create a postbuild step that copies the correct file depending on the build type.我认为您想要的是在运行时换出配置文件的一个版本,如果是这样,请创建具有正确地址的配置文件的副本(也给它相关的扩展名,如 .Debug 或 .Release)(这会给您一个调试版本和一个运行时版本)并创建一个 postbuild 步骤,根据构建类型复制正确的文件。

Here is an example of a postbuild event that I've used in the past which overrides the output file with the correct version (debug/runtime)这是我过去使用的 postbuild 事件的示例,它使用正确的版本(调试/运行时)覆盖输出文件

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

where : $(ProjectDir) is the project directory where the config files are located $(ConfigurationName) is the active configuration build type其中: $(ProjectDir) 是配置文件所在的项目目录 $(ConfigurationName) 是活动的配置构建类型

EDIT: Please see Marc's answer for a detailed explanation on how to do this programmatically.编辑:有关如何以编程方式执行此操作的详细说明,请参阅 Marc 的回答。

see if you are placing the client section in the correct web.config file.查看您是否将客户端部分放置在正确的 web.config 文件中。 SharePoint has around 6 to 7 config files. 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 ) 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 )

Post this you can simply try发布这个你可以简单地尝试

ServiceClient client = new ServiceClient("ServiceSOAP");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM