Using WCF on Localhost on Azure

2020-06-03 07:13发布

问题:

In summary
How do I acces a WCF service on localhost when hosted in IIS on Azure? Azure does not bind localhost or 127.0.0.1 to my website.

Details
I have an ASP.Net application hosted on Azure. I have added a .svc and some workflows that I want to use via WCF. To keep matters simple, my web app simply calls the service on localhost, so I have endpoints like these in web.config;

<client>
  <endpoint address="http://localhost:8080/Router.svc/Case" binding="basicHttpBinding" contract="NewOrbit.ExVerifier.Model.Workflow.Case.ICaseWorkflow" name="Case" />
  <endpoint address="http://localhost:8080/Workflow/Case/Case_default1.xamlx" binding="basicHttpBinding" contract="*" name="Case_default1" />
</client>

This works just fine on my local machine. The problem is that when I publish this to Azure, the Website in IIS does not get a binding to localhost, instead the bindings are always to the actual IP address of the server. It ends up looking like this in applicationHost.config:

<bindings>
   <binding protocol="http" bindingInformation="10.61.90.44:80:" />
   <binding protocol="https" bindingInformation="10.61.90.44:443:" />
   <binding protocol="http" bindingInformation="10.61.90.44:8081:" />
</bindings>

So, as soon as my web app tries to call the service on localhost (or 127.0.0.1 for that matter) it fails instantly. Needless to say, if I rdp on to the server and change the binding then all is fine.

What I find really odd is that there are tons of examples out there where people are accessing WCF services on localhost on Azure so I can't figure out why this is so. I have set the osFamily to 2 and in order to debug this I have enabled web publishing and remote desktop access which I guess, in theory, could mess things up.

What I have already looked at

  • I can rewrite the end-point address in my code at runtime to substitute localhost for the actual address or create the endpoint dynamically as described by Ron in the answers. Unfortunately I am using the WCF Routing service so I can version workflows. This means that my code calls the Router endpoint and the WCF Router in turns calls the actual service/workflow using an endpoint specified in web.config. I don't have control over the Routing services endpoint resolution without, I think, writing a whole set of routing logic which just seems to be a lot of work when all I want is to call localhost :)
  • Switching to using named pipes; Alas, it causes some strange issues with workflows, probably due to duplexing, and I am on a deadline so haven't got time to get to the bottom of that at the minute.

回答1:

You have to build the endpoint address dynamically.

Step 1: In your ServiceDefinition.csdef you need to declare an Endpoint.

<ServiceDefinition name="MyFirstAzureWorkflow" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="WorkflowWeb" vmsize="ExtraSmall">
    <Sites>
      <Site name="Web">
        <Bindings>
          <Binding name="Endpoint1" endpointName="WorkflowService" />
        </Bindings>
      </Site>
    </Sites>
    <Endpoints>
      <InputEndpoint name="WorkflowService" protocol="http" port="80" />
    </Endpoints>
    <Imports>
      <Import moduleName="Diagnostics" />
    </Imports>
  </WebRole>
</ServiceDefinition>

Step 2: When you want to call the service

var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["WorkflowService"].IPEndpoint;
var uri = new Uri(string.Format(
    "http://{0}:{1}/MyService.xamlx",
    endpoint.Address,
    endpoint.Port));
var proxy = new ServiceClient(
    new BasicHttpBinding(),
    new EndpointAddress(uri));


回答2:

Okay, so this is how I solved it. IMHO it's a hack but at least it works.

Basically, I need to add a "*" binding, so I can do this in Powershell. The general recipe is here: http://blogs.msdn.com/b/tomholl/archive/2011/06/28/hosting-services-with-was-and-iis-on-windows-azure.aspx

That deals with adding Named Pipes support, but the principle is the same. I just changed the Powershell script to:

import-module WebAdministration
# Set up a binding to 8080 for the services 
Get-WebSite "*Web*" | Foreach-Object { 
  $site = $_;
  $siteref = "IIS:/Sites/" + $site.Name;
  New-ItemProperty $siteref -name bindings -value @{protocol="http";bindingInformation="*:8080:"}
}

This now allows me to use http://127.0.0.1:8080/service.svc to access my service.

Note: You do need to follow the rest of the recipe to set elevated execution context and change the powershell execution mode, so do follow it carefully