If you are like me and you’ve:
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:
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:
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.