ASP.NET WebApi SelfHost服务在HTTP URL注册时失败

时间:2012-06-28 07:25:25

标签: c# wcf azure asp.net-web-api wcf-web-api

我正在尝试使用新的Microsoft.AspNet.WebApi.SelfHost NuGet包在Azure辅助角色上托管ASP.NET WebApi端点。我的worker的Run()代码大致如下:

// 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);

这在开发结构中工作正常,但在部署到Azure时,我从server.OpenAsync()调用获得了一个AggregateException,其中包含以下异常堆栈:

[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

我只是扮演一个香草工人的角色,这似乎是"你好世界"自我主持......

我的ServiceDefinition.csdef的端点部分如下所示:

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

我从RoleEnvironment InstanceEndpoint获取的baseAddress看起来合法 - http://10.115。[X]。[Y]:8081

我看到失败是否使用相同的端口/ localPort(8080)或执行映射时,如上所述。

很明显,以这种方式可以在工作者角色中托管传统的WCF服务 - ASP.NET WebApi SelfHost在这种配置中不起作用的原因是什么?

3 个答案:

答案 0 :(得分:4)

默认情况下,RoleEntryPoint在非常小的权限用户帐户下运行以确保安全性。如错误所示,由于这些权限,它无法保留该端口。你有两个选择:

  1. 通过将Runtime元素添加到角色定义(即<Runtime executionContext="elevated"/>),将Worker进程作为SYSTEM运行。
  2. 创建一个运行提升的启动脚本,并为您保留该端口。
  3. 对于游戏(如果是权限问题进行故障排除),执行#1是一种快速测试方法。

    编辑:在执行通配符保留时,我似乎回想起WCF和Windows Azure的权限问题。它曾经在使用完整的主机名时工作正常,例如。

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

答案 1 :(得分:2)

在半天的开发日试验从提升的启动脚本调用netsh.exe无济于事后,我放弃并最终使用大锤并采取Ryan的初步建议来运行整个工作者角色:

<WorkerRole name="WorkerRole" vmsize="ExtraSmall">
  <Runtime executionContext="elevated">
  </Runtime>
</WorkerRole>

解决了所有问题。

作为参考,以下是我尝试为非提升用户帐户(从未真正起作用)允许HTTP注册的方式:

在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>

在启动脚本中(在我的情况下是startup \ Install.cmd):

netsh.exe http add urlacl url=http://+:%ENDPOINTPORT%/api user=everyone listen=yes delegate=yes

这基本上是处理AspNetWebApi的优秀人员所推荐的解决方案(只是做他们推荐的here的一种较短的方式),但不幸的是它对我不起作用 - 同时执行了netsh命令成功了,我能够验证我自己托管的URL上的urlacl(http:// +:8080 / api /)是否允许\ Everyone,我仍然得到相同的权限错误。如果有人在运行非工作角色时弄清楚如何使这项工作,请发帖!

答案 2 :(得分:-1)

添加引用&#39; System.ServiceModel&#39;到您的项目并使用&#39; config.HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.Exact;&#39;您没有获得管理员权限异常(访问被拒绝)。