I host a WCF service in an Azure worker role.
The service is accessible at the public domain name of the cloud services instance (myservice.cloudapp.net), however, the links to the WSDL, and the URLs inside the WSDL use the internal IP address instead, that cannot be accessed from outside. Thus tools like Add service reference and WCFTestClient.exe does not work as smoothly as they should, because they try to access the internal IP address.
I am creating my service with the following code:
RoleInstanceEndpoint endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["MyServiceEndpoint"];
string endpointAddr = String.Format( "http://{0}/MyInteropService", endpoint.IPEndpoint );
this.serviceHost = new ServiceHost( typeof( MyInteropService ), new Uri( endpointAddr ) );
BasicHttpBinding binding = new BasicHttpBinding();
serviceHost.AddServiceEndpoint( typeof( IMyInteropService ), binding, "" );
ServiceMetadataBehavior smb = new ServiceMetadataBehavior
{
HttpGetEnabled = true,
HttpsGetEnabled = true,
};
serviceHost.Description.Behaviors.Add( smb );
//serviceHost.AddServiceEndpoint( ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); It does not matter whether I include this line or not.
serviceHost.Open();
What am I doing wrong? How should I configure the service to use the public domain name in the WSDL as well?
UPDATE: Peter's answer helped me solve the problem, in my case I only had to add a UseRequestHeadersForMetadataAddressBehavior
behavior to the service, after that the WSDL used the public domain name (I guess now it uses the domain the client is sending the request to).
So the complete working code is the following:
RoleInstanceEndpoint endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["MyServiceEndpoint"];
string endpointAddr = String.Format( "http://{0}/MyInteropService", endpoint.IPEndpoint );
this.serviceHost = new ServiceHost( typeof( MyInteropService ), new Uri( endpointAddr ) );
BasicHttpBinding binding = new BasicHttpBinding();
serviceHost.AddServiceEndpoint( typeof( IMyInteropService ), binding, "" );
ServiceMetadataBehavior smb = new ServiceMetadataBehavior
{
HttpGetEnabled = true,
HttpsGetEnabled = true,
};
serviceHost.Description.Behaviors.Add( smb );
// This part solved the problem.
var requestHeaderBehavior = new UseRequestHeadersForMetadataAddressBehavior();
this.serviceHost.Description.Behaviors.Add(requestHeaderBehavior);
serviceHost.Open();
Edit: my situation was complicated a bit by the security binding I believe, it may be a bit easier for you
Okay, so there's a few issues here. I'll see if I can remember them all correctly.
Firstly, to expose the endpoints in the manner that you wish you don't actually have the correct permissions to do so (even if you run in an elevated context - which you will still need to do). It'll throw an internal error when it tries to register the endpoint.
I had to change the application pool user that did have the rights to do it (it'll be the same credentials as those you use to rdp to the worker roles.
This gave me the ability to configure the service like below, you may need to modify it to your needs. Pay close attention to settings marked important as I believe these are vital in exposing your service.
Some bits omitted etc. This took a seriously long time to figure out and a lot of grey hairs.