7

我正在尝试使用新的 Microsoft.AspNet.WebApi.SelfHost NuGet 包在 Azure 辅助角色上托管 ASP.NET WebApi 端点。我的工作人员的 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

无论我使用相同的端口/本地端口(8080)还是进行映射时,我都会看到失败,就像上面一样。

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

4

3 回答 3

4

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

  1. 通过将 Runtime 元素添加到您的角色定义(即<Runtime executionContext="elevated"/>),以 SYSTEM 身份运行 Worker 进程。
  2. 创建一个运行提升的启动脚本并为您保留该端口。

对于玩耍(以及如果是权限问题进行故障排除),执行 #1 是一种快速测试它的方法。

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

host.AddServiceEndpoint(
 typeof(IEchoService), new BasicHttpBinding(BasicHttpSecurityMode.None) { HostNameComparisonMode = HostNameComparisonMode.Exact }, "echo");
于 2012-06-28T16:54:39.993 回答
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 上工作的好人推荐的解决方案(只是他们在此处推荐的一种更短的方法),但不幸的是它对我不起作用 - 而 netsh 命令成功执行并且我能够验证我自托管的 URL (http://+:8080/api/) 上的 urlacl 是由 \Everyone 允许的,我仍然遇到相同的权限错误。如果有人在运行非提升的工人角色时弄清楚如何使这项工作,请发布!

于 2012-06-28T21:41:46.163 回答
-1

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

于 2014-09-16T09:20:24.223 回答