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

Posted

技术标签:

【中文标题】ASP.NET WebApi SelfHost 服务在 HTTP URL 注册上失败【英文标题】:ASP.NET WebApi SelfHost service fails on HTTP URL registration 【发布时间】:2012-06-29 16:37:27 【问题描述】:

我正在尝试使用新的 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 在此配置中不起作用?

【问题讨论】:

【参考方案1】:

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

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

为了玩弄(如果是权限问题则进行故障排除),执行 #1 是一种快速测试方法。

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

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

【讨论】:

嘿瑞恩 - 非常感谢!我认为这是一些许可问题。 #1 是一把相当大的锤子......如果需要,我会这样做,但我希望做一些更外科手术......比如在提升的启动脚本中运行 netsh - 比如“netsh.exe http add urlacl url="http://+:8080" 但我需要向用户授予权限,而且我真的不知道 Azure 将在其下运行辅助角色的帐户的名称/SID... 是否有如何找出答案,或者以允许所有用户访问该端口的方式运行 netsh.exe? 嗯...现在我仔细看,我认为这是因为您正在进行通配符预订。如果您刚刚更新代码以针对确切的 IP 地址和端口,我认为您可以解决权限问题。 IIRC,只有通配符保留需要提升到 ACL。查看更新的答案。 当我在上面的代码中跟踪“baseAddress”的值时,它会变成这样:10.115.210.79:8080。所以我实际上使用的是完全匹配......此外,奇怪的是,即使我在启动脚本中添加了一行“netsh.exe http add urlacl url="http://+:8080" user =everyone”,并验证它是否正确执行(并且当我执行“netsh http urlacl show”时权限是否正确),我仍然得到同样的错误。【参考方案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 (http://+:8080/api/) 上的 urlacl 是否被 \Everyone 允许,但我仍然遇到相同的权限错误。如果有人在运行非提升的工人角色时弄清楚如何使这项工作发挥作用,请发帖!

【讨论】:

我在 cmd 中运行了一次脚本,但我必须以管理员身份运行:您以谁的身份运行启动脚本?另一个参考here 默认情况下,Azure 不会在提升的帐户中运行其角色,而是在没有可预测名称的相当受限的用户帐户中运行(它们是在结构控制器准备 VM 时创建的 GUID)。 Azure 确实允许在提升的(管理员)帐户中运行启动脚本——这就是我代码中的 > 所做的。但由于某种原因,netsh.exe 仍然没有成功允许该命令。我最终不得不提升整个角色(这解决了问题)。 糟糕,抱歉,我跳过了“Azure”细节!【参考方案3】:

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

【讨论】:

请稍作评论?

以上是关于ASP.NET WebApi SelfHost 服务在 HTTP URL 注册上失败的主要内容,如果未能解决你的问题,请参考以下文章

asp.net web api 自托管 / owin / katana

如何在 ASP.NET Web API SelfHost 应用程序中使用 CORS?

WebAPi之SelfHost启动Https疑难解惑及无法正确返回结果

运行WebApi项目的OWIN SelfHost项目不调用Application_Start方法

WEB API 2,Selfhost,除“localhost”外的所有内容都拒绝访问

Autofac 错误:无法加载文件或程序集 'System.Web.Http, Version=5.2.0.0,...' 我的项目是 Owin WebApi2 SelfHost