Asp.net Самостоятельная служба WCF WSDL с относительными путями

Я работаю над приложением WCF, которое будет разворачиваться на различных серверах по пути, и мне бы хотелось, чтобы мне не приходилось помнить об изменении app.config каждый раз, когда я выполняю развертывание. Сначала мой раздел serviceModel app.config выглядел так:

<system.serviceModel>  
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />  
<behaviors>  
    <serviceBehaviors>  
        <behavior name="MyDefaultServiceBehavior">   
            <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8888/MyService" />  
            <serviceDebug includeExceptionDetailInFaults="true" />  
        </behavior>  
    </serviceBehaviors>  
</behaviors>  
<services>  
    <service behaviorConfiguration="MyDefaultServiceBehavior" name="MyService">   
        <endpoint address="net.tcp://localhost:9001/MyService" binding="netTcpBinding" contract="IMyService" name="NetTcpBinding_IMyService" />  
    </service>  
</services>  

Это отлично работает при разработке, когда я обращался к службе, запущенной на моем локальном компьютере. Когда я его развернул, WSDL содержал абсолютные пути, которые все еще указывали на localhost:

<xsd:import schemaLocation=http://localhost:8888/MyService?xsd=xsd0 namespace="http://tempuri.org/" />

Итак, я могу изменить httpGetUrl в app.config следующим образом:

<serviceMetadata httpGetEnabled="true" httpGetUrl=http://devserver1:8888/MyService />

И теперь wsdl корректно работает на этом сервере. Проблема в том, что мне приходится вручную устанавливать адрес в каждом развернутом app.config.

Есть ли способ:
1. Включить уже все в wsdl, чтобы не было импорта?
или
2. Использовать относительные пути в операторах импорта wsdl?

Или любые другие предложения будут оценены. У меня есть два сервера разработки, на которых развертывание автоматизировано, если бы не проблема с wsdl.

Поскольку это только для генерации прокси, я полагаю, я мог бы сгенерировать прокси и распространить его сам, но я бы предпочел позволить пользователям генерировать прокси самостоятельно.

Спасибо! Даниэль

Ответов (3)

Решение

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

Я изменил свой app.config на httpGetUrl, содержащий myServiceServer:

<serviceMetadata httpGetEnabled="true" httpGetUrl=http://myServiceServer:8888/MyService />

Чтобы использовать мою службу, кто-то должен сначала добавить в файл хоста запись, которая сопоставляет myServiceServer с правильным IP-адресом. Это хорошо работает для нашей проблемы, потому что IP-адрес не может быть определен с помощью любого общего имени машины или IP-адреса. Это происходит из-за разделенных сетей, которые связаны только через VPN с каким-то NAT.

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

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

Чтобы включить его, добавьте следующий код в то же место, где вы добавляете ServiceMetadataBehavior :

host.Description.Behaviors.Remove<UseRequestHeadersForMetadataAddressBehavior>();
host.Description.Behaviors.Add(new UseRequestHeadersForMetadataAddressBehavior());

Вы можете установить значение httpGetUrl программно и установить для него абсолютный адрес, который включает имя компьютера сервера, на котором размещаются службы. Операторы импорта в сгенерированном WSDL также будут использовать машинное имя сервера.

Если ваш хост WCF создается для вас (например, вы размещаете в IIS), вам нужно будет создать настраиваемый ServiceHostFactory, чтобы получить доступ к ServiceHost . Например:

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Description;

namespace WebApplication
{
  public class TestServiceHostFactory : ServiceHostFactory
  {
     protected override ServiceHost CreateServiceHost(Type serviceType, 
                                                      Uri[] baseAddresses)
      {
        ServiceHost host = base.CreateServiceHost(serviceType, 
                                                  baseAddresses);
        ServiceMetadataBehavior metadataBehavior = 
                                new ServiceMetadataBehavior();
        metadataBehavior.HttpGetEnabled = true;
        metadataBehavior.HttpGetUrl = new Uri(string.Format(
                              "http://{0}/WebApplication/TestService.svc", 
                              Environment.MachineName));
        host.Description.Behaviors.Add(metadataBehavior);
        return host;
      }
  }
}

Затем вы указываете эту фабрику в файле .svc службы:

<%@ ServiceHost Language="C#" 
                Service="WebApplication.TestService" 
                CodeBehind="TestService.svc.cs" 
                Factory="WebApplication.TestServiceHostFactory" %>

Если вы сами создаете узел WCF, ваш код будет выглядеть примерно так:

ServiceHost host = new ServiceHost(typeof(WebApplication.TestService));
ServiceMetadataBehavior metadataBehavior = new ServiceMetadataBehavior();
metadataBehavior.HttpGetEnabled = true;
metadataBehavior.HttpGetUrl = new Uri(string.Format(
                              "http://{0}/WebApplication/TestService.svc", 
                              Environment.MachineName));
host.Description.Behaviors.Add(metadataBehavior);