Как программно изменить настройки адреса конечной точки WCF app.config? - PullRequest
49 голосов
/ 08 июня 2009

Я бы хотел программно изменить файл 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>

Ответы [ 11 ]

95 голосов
/ 08 июня 2009

Это на стороне клиента вещей ??

Если это так, вам нужно создать экземпляр 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>

(три разных имени, разные параметры, указав разные привязки конфигурации), а затем просто выберите правильное для создания экземпляра вашего сервера (или прокси клиента).

Но в обоих случаях - сервер и клиент - вы должны выбрать, прежде чем создавать сервисный хост или прокси-клиент. После создания они неизменны - вы не можете настроить их, как только они будут запущены.

Марк

26 голосов
/ 15 января 2010

Я использую следующий код для изменения адреса конечной точки в файле 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";
        }
    }
}
11 голосов
/ 20 февраля 2012
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 .

5 голосов
/ 08 апреля 2014

у меня этот короткий код работал:

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.Configuration и System.ServiceModel , чтобы эта работа работала.

Приветствия

2 голосов
/ 20 декабря 2012

Это самый короткий код, который вы можете использовать для обновления файла конфигурации приложения, даже если не определен раздел конфигурации:

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");
}
2 голосов
/ 10 сентября 2012

Я изменил и расширил код Malcolm Swaine для изменения определенного узла по его атрибуту name, а также для изменения внешнего файла конфигурации. Надеюсь, это поможет.

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

}

1 голос
/ 04 августа 2015

Для этого мне нужно было обновить порт и схему для SSL для моей службы RESTFul. Это то, что я сделал. Извиняюсь, что это немного больше, чем первоначальный вопрос, но, надеюсь, кому-то пригодится.

// 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();
1 голос
/ 27 января 2015

Вы можете сделать это так:

  • Храните настройки в отдельном 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();
    
1 голос
/ 02 декабря 2013
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 }

Очень легко изменить URI в конфигурации или информацию о привязке в конфигурации. Это то, что вы хотите?

1 голос
/ 08 июня 2009

Я думаю, что вам нужно поменять во время выполнения версию вашего конфигурационного файла, если это так, создайте копию вашего конфигурационного файла (также дайте ему соответствующее расширение, например .Debug или .Release), которое имеет правильные адреса ( который дает вам отладочную версию и версию времени выполнения) и создает шаг пост-сборки, который копирует правильный файл в зависимости от типа сборки.

Вот пример события пост-сборки, которое я использовал в прошлом, которое заменяет выходной файл правильной версией (отладка / время выполнения)

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

где: $ (ProjectDir) - это каталог проекта, в котором находятся файлы конфигурации $ (ConfigurationName) - тип сборки активной конфигурации

EDIT: Пожалуйста, смотрите ответ Марка для подробного объяснения того, как сделать это программно.

...