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?
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:
<Runtime executionContext="elevated"/>
).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");
After half a dev-day experimenting with invoking netsh.exe from an elevated startup script to no avail, I gave up and ended up using the big hammer and taking Ryan's initial suggestion of running the entire worker role elevated:
<WorkerRole name="WorkerRole" vmsize="ExtraSmall">
<Runtime executionContext="elevated">
</Runtime>
</WorkerRole>
That solved all issues.
For reference, here is how I tried to allow HTTP registration for non-elevated user accounts (which never really worked):
In ServiceDefinition.csdef:
<Startup>
<Task executionContext="elevated" commandLine="startup\Install.cmd">
<Environment>
<Variable name="ENDPOINTPORT ">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[@name='Endpoint']/@port" />
</Variable>
</Environment>
</Task>
</Startup>
<Endpoints>
<InputEndpoint name="Endpoint" protocol="http" port="8080" localPort="8080" />
</Endpoints>
And in the startup script (startup\Install.cmd in my case):
netsh.exe http add urlacl url=http://+:%ENDPOINTPORT%/api user=everyone listen=yes delegate=yes
This is basically the solution that was recommended by the good folks working on AspNetWebApi (just a shorter way of doing what they recommend here), but unfortunately it didn't work for me - while the netsh command executed successfully and I was able to verify that the urlacl on the URL I am self-hosting on (http://+:8080/api/) is allowed by \Everyone, I was still getting the same permission error. If anyone figures out how to make this work when running the worker-role non-elevated, please post!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With