Wcf – Asp.net Self Hosted WCF Service WSDL with relative paths

asp.netwcfwsdl

I am working on a WCF application that will be deployed to various servers along the way and I would like to not have to remember to change the app.config every time I do a deployment. At first, my app.config serviceModel section looked like this:

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

This works fine in development when I was accessing the service running on my local machine. When I deployed it, the WSDL contained absolute paths that still pointed to localhost:

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

So, I can change the httpGetUrl in the app.config like so:

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

And now the wsdl works correctly on that server. The problem is that I have to manually set the address in each app.config that gets deployed.

Is there a way to either:
1. Have the wsdl already include everything so that there are no imports?
or
2. Use relative paths in the wsdl import statements?

Or any other suggestions would be appreciated. I have two development servers that the deployment is automated to, if only it weren't for this wsdl problem.

Since this is only for generating the proxy, I suppose I could generate the proxy and distribute it myself, but I'd rather let users generate the proxy themselves.

Thanks!
Daniel

Best Answer

You could set the value of httpGetUrl programatically and set it to an absolute address that includes the machine name of the server of that the services are being hosted on. The import statements in the generated WSDL will then also use the machine name of the server.

If your WCF host is being created for you (for example, you are hosting under IIS) then you will need to create a custom ServiceHostFactory to get access to the ServiceHost. For example:

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

You then specify this factory in the .svc file of the service:

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

If you are creating the WCF host yourself then your code would look something like this:

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);
Related Topic