|||

WCF service NETBIOS name resolution woes

If you are like me and you’ve:

  • Created a WCF service that is hosted within a windows process.
  • Configured the WCF service in code, instead of a config file.
  • Exposed this service via the internet to a 3rd party (via router port forwarding for initial testing)
  • Used basic http binding.

It all works fine, if you try to generate the service proxy (using svcutil.exe) from the local network, but the 3rd party complains that they can’t. Although they can see the default service help/greeting page when they view it in a browser.

Following is a simple Helloworld ServiceContract i created, which replicated the problem:

[ServiceContract(Namespace = "http://raghurana.com/blog/Demos/Wcf")]
public interface IHelloWorldService
{
    [OperationContract]
    string SayHelloWorld();
}
 
public class HelloWorldService : IHelloWorldService
{
    public string SayHelloWorld()
    {
        return "Hello World.";
    }
}

and this is how my Service Host class looked like, which had the in code service configuration:

public sealed class HelloWorldServiceHost : IDisposable
{
    const string serviceAddress = "http://localhost/hwservice.svc";
 
    private ServiceHost svcHost;
 
    public HelloWorldServiceHost()
    {
        svcHost = new ServiceHost( typeof(HelloWorldService), new[] { new Uri(serviceAddress)  } );
 
        var metadataBehavior = svcHost.Description.Behaviors.Find() ?? new ServiceMetadataBehavior();
 
        metadataBehavior.HttpGetEnabled = true;
 
        svcHost.Description.Behaviors.Add( metadataBehavior );
 
        svcHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
 
        svcHost.AddServiceEndpoint(typeof (IHelloWorldService), new BasicHttpBinding(), serviceAddress);
    }
 
    ~HelloWorldServiceHost()
    {
        Dispose(false);
    }
 
    public void StartListening()
    {
        svcHost.Open();
    }
 
    public void StopListening()
    {
        svcHost.Close();
    }
 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
 
    private void Dispose(bool isExplicitInvocation)
    {
        if(isExplicitInvocation)
        {
            if(svcHost != null)
            {
                (svcHost as IDisposable).Dispose();
 
                svcHost = null;
            }
        }
    }
}

I then created a console app, instantiated the HelloWorldServiceHostClass and ran the app and i could see the output in browser:

sc

As highlighted in the picture above, 192.168.1.4 is my local IP address of the intranet and when i exposed this service to the 3rd party they were invoking the service by the external/internet IP which was something like 60.230..

They could see the service help/greeting page in the browser but the page was also showing

svcutil.exe http://localhost/hwservice.svc?wsdl

and there was no hwservice.svc service hosted on localhost of the 3rd party’s test machine. This behaviour is due to the fact that WCF uses the computer name or the NETBIOS name of the machine it is hosted on.

The fix for this problem was quite simple, once i found out what it was. All I had to do was modify my HelloWorldServiceHost class’s constructor as follows:

public HelloWorldServiceHost()
{
    svcHost = 
        new ServiceHost(typeof(HelloWorldService), 
                        new[] { new Uri(serviceAddress) });

    var metadataBehavior = 
        svcHost.Description.Behaviors.Find() 
            ?? new ServiceMetadataBehavior();

    metadataBehavior.HttpGetEnabled = true;

    svcHost.Description.Behaviors.Add(metadataBehavior);

    svcHost.AddServiceEndpoint(
        ServiceMetadataBehavior.MexContractName, 
        MetadataExchangeBindings.CreateMexHttpBinding(), 
        "mex");

    svcHost.AddServiceEndpoint(
        typeof(IHelloWorldService), 
        new BasicHttpBinding(), 
        serviceAddress);

    // New code added
    var requestHeaderBehavior = 
        new UseRequestHeadersForMetadataAddressBehavior();

    // Since the service is exposed over http and 80 in this instance.
    requestHeaderBehavior.DefaultPortsByScheme.Add("http", 80);

    // add this new behavior to the service.
    svcHost.Description.Behaviors.Add(requestHeaderBehavior);
}

Re-compiled > Re-ran the console app > hit refresh on the browser > and:

sc

Having the same request IP address in the svcutil help line assured that the service metadata will be exposed to the 3rd party via 60.230.. address, instead of localhost and indeed that was the case.

Since the machine on which this process ran only had upto .net 3.5 sp1 installed, i had to download and install this hotfix from the MS support website. This hotfix contains the class libraries in which UseRequestHeadersForMetadataAddressBehavior class is defined.

Up next The troublesome Git-Svn Marriage How I diagnosed High CPU usage using Windbg
Latest posts Flutter CI/CD with Azure Devops & Firebase - iOS - Part 1 Flutter CI/CD with Azure Devops & Firebase - Android - Part 2 How to samples with AWS CDK A hashicorp packer project to provision an AWS AMI with node, pm2 & mongodb Some notes on Zeebe (A scalable process orchestrator) Docker-Compose in AWS ECS with EFS volume mounts Domain Driven Design Core Principles Apple Push Notifications With Amazon SNS AWS VPC Notes Building and Deploying apps using VSTS and HockeyApp - Part 3 : Windows Phone Building and Deploying apps using VSTS and HockeyApp - Part 2 : Android Building and Deploying apps using VSTS and HockeyApp - Part 1 : iOS How I diagnosed High CPU usage using Windbg WCF service NETBIOS name resolution woes The troublesome Git-Svn Marriage GTD (Getting things done) — A simplified view Javascript Refresher Sharing common connection strings between projects A simple image carousel prototype using Asp.net webforms and SignalR Simple logging with NLog Application logger SVN Externals — Share common assembly code between solutions Simple async in .net 2.0 & Winforms Clean sources Plus Console 2 — A tabbed console window