Search code examples
c#wcfazureasp.net-web-apiwcf-web-api

ASP.NET WebApi SelfHost service fails on HTTP URL registration


I am trying to host an ASP.NET WebApi endpoint on an Azure worker role using the new Microsoft.AspNet.WebApi.SelfHost NuGet package. My worker's Run() code looks roughly like this:

// Endpoint is defined as in ServiceDefinition.csdef as 
//   HTTP, external port 8080, internal port 8080 (or 8081 - error both ways)
RoleInstanceEndpoint externalEndPoint =
    RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["Endpoint"]; 
string baseAddress= String.Format("http://{0}", externalEndPoint.IPEndpoint);
var maxsize = 1024 * 1024;  
var config = new HttpSelfHostConfiguration(baseAddress) 
{ 
    MaxBufferSize = maxsize, MaxReceivedMessageSize = maxsize 
};
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

// Create and open the server
var server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();

// keep the worker thread alive
while (true)
    Thread.Sleep(Timeout);

This works fine in the dev fabric, but when deploying to Azure, I get an AggregateException from the server.OpenAsync() call, containing the following exception stack:

[0] One or more errors occurred.
[1] HTTP could not register URL http://+:8081/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).
[2] Access is denied

I'm just running a vanilla worker role and this seems to be the "hello world" of self-host...

The endpoint part of my ServiceDefinition.csdef looks like this:

<Endpoints>
  <InputEndpoint name="Endpoint" protocol="http" port="8080" localPort="8081" />
</Endpoints>

The baseAddress that I get from the RoleEnvironment InstanceEndpoint looks legit - http://10.115.[X].[Y]:8081

I see the failure whether I use the same port/localPort (8080) or when I do a mapping, like the above.

It's clear that it's possible to host a conventional WCF service in a worker role in this way - is there any reason why ASP.NET WebApi SelfHost wouldn't work in this configuration?


Solution

  • By default, the RoleEntryPoint runs under a very minimal permission user account for security. As the error indicates, it is unable to reserve that port due to those permissions. You have two options here:

    1. Run the Worker process as SYSTEM by adding the Runtime element to your role definition (i.e <Runtime executionContext="elevated"/>).
    2. Create a startup script that runs elevated and reserves that port for you.

    For playing around (and troubleshooting if it is a permission issue), doing #1 is a quick way to test it.

    Edit: I seem to recall a permission issue with WCF and Windows Azure when doing wildcard reservations. It used to work fine when using the full hostname e.g.

    host.AddServiceEndpoint(
     typeof(IEchoService), new BasicHttpBinding(BasicHttpSecurityMode.None) { HostNameComparisonMode = HostNameComparisonMode.Exact }, "echo");