Asp.net自托管WCF服务WSDL与相对路径

时间:2009-02-25 20:03:17

标签: asp.net wcf wsdl

我正在开发一个WCF应用程序,它将在整个部署过程中部署到各种服务器上,我不想记得每次部署时都更改app.config。起初,我的app.config serviceModel部分看起来像这样:

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

所以,我可以改变app.config中的httpGetUrl,如下所示:

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

现在wsdl在该服务器上正常工作。问题是我必须在每个部署的app.config中手动设置地址。

有没有办法: 1. wsdl已经包含了所有内容,以便没有进口吗? 或
2.在wsdl import语句中使用相对路径?

或者任何其他建议将不胜感激。我有两个部署自动化的开发服务器,如果不是这个wsdl问题。

由于这仅用于生成代理,我想我可以生成代理并自己分发代理,但我宁愿让用户自己生成代理。

谢谢! 丹尼尔

3 个答案:

答案 0 :(得分:3)

您可以以编程方式设置httpGetUrl的值,并将其设置为一个绝对地址,其中包含托管服务的服务器的计算机名称。然后,生成的WSDL中的import语句也将使用服务器的机器名。

如果您正在为自己创建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);

答案 1 :(得分:2)

Daniel Richardson上面留下的答案很好,我认为对大多数人来说,这将是首选的解决方案。但是,由于我们的网络布局和需要访问我们服务器的人很少,我做的事情有点不同。

我已将app.config更改为包含“myServiceServer”的httpGetUrl:

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

要使用我的服务,必须先添加将“myServiceServer”映射到正确IP地址的主机文件条目。这适用于我们的问题,因为无法从任何常见的计算机名称或IP地址解析IP地址。这是因为分离的网络仅通过VPN连接,并且正在进行某种NAT。

答案 2 :(得分:0)

显然,WCF内置了一个非常隐蔽的选项,该选项支持使用与传入请求相同的主机名,这通常是正确的。 (我认为不是默认值的唯一原因是为了向后兼容,尽管如果他们仍然将其设为默认值可能会更好。)

在找到这种特殊的宝石之前,花了很多时间来寻找头发(尽管现在我知道了这个神奇的词,但我发现another answer是来自与我相似的旅程)

要启用它,请在添加ServiceMetadataBehavior的同一位置添加以下代码:

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