2012-06-28 29 views
7

Estoy tratando de alojar un punto final ASP.NET WebApi en una función de trabajador de Azure utilizando el nuevo paquete Microsoft.AspNet.WebApi.SelfHost NuGet. Ejecutar código de mi trabajador() se ve más o menos así:ASP.NET WebApi El servicio SelfHost falla en el registro URL HTTP

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

Esto funciona bien en el tejido dev, pero cuando se despliega en Azure, me sale un AggregateException de la llamada server.OpenAsync(), que contiene la siguiente pila de excepción :

[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 

sólo estoy corriendo un papel trabajador de vainilla y este parece ser el "hola mundo" de la auto-anfitrión ...

el criterio de valoración parte de mi ServiceDefinition.csdef se ve así:

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

El baseAddress que recibo de la RoleEnvironment InstanceEndpoint parece de fiar - http:.. //10.115 [X] [Y]: 8081

veo el fracaso si utilizo el mismo puerto/localPort (8080) o cuando hago un mapeo, como el anterior.

Está claro que es posible alojar un servicio WCF convencional en una función de trabajo de esta manera: ¿hay alguna razón por la cual ASP.NET WebApi SelfHost no funcionaría en esta configuración?

Respuesta

4

De forma predeterminada, RoleEntryPoint se ejecuta con una cuenta de usuario con permisos mínimos para la seguridad. Como indica el error, no puede reservar ese puerto debido a esos permisos. Usted tiene dos opciones aquí:

  1. ejecutar el proceso de trabajo como sistema añadiendo el elemento de tiempo de ejecución a la definición de funciones (es decir <Runtime executionContext="elevated"/>).
  2. Crea un script de inicio que se ejecuta elevado y lo reserva para ti.

Para jugar (y solucionar problemas si se trata de un problema de permiso), hacer # 1 es una manera rápida de probarlo.

Editar: Me parece recordar un problema de permiso con WCF y Windows Azure al hacer reservas de comodines. Solía ​​funcionar bien cuando se utilizaba el nombre de host completo, p.

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

Hola Ryan, muchas gracias! Pensé que era un problema de permisos. # 1 es un martillo bastante grande ... Lo haré si fuera necesario, pero esperaba hacer algo un poco más quirúrgico ... como ejecutar netsh en un guion de inicio elevado, algo así como "netsh.exe http add" urlacl url = "http: // +: 8080" pero necesito otorgar permiso a un usuario, y realmente no sé el nombre/SID de la cuenta en la que Azure ejecutará el rol de trabajador ... ¿hay alguna forma de averiguarlo, o ejecutar netsh.exe de una manera que permita el acceso en ese puerto a todos los usuarios? –

+0

Hmm ... ahora que miro más de cerca, creo que es porque estás haciendo una reserva de comodín. Solo actualicé el código para apuntar a la dirección IP y el puerto exactos, creo que puede evitar el problema de permisos. IIRC, solo son las reservas de comodines las que deben elevarse a ACL. Consulte la respuesta actualizada. – dunnry

+0

Cuando trace el valor de " baseAddress "en el código anterior, sale así: http://10.115.210.79:8080. Así que en realidad estoy usando una coincidencia exacta ... además, lo extraño es que incluso si agrego una línea al script de inicio que hace "netsh.exe http add urlacl url =" http: // +: 8080 "user = everyone", y verifica que se ejecuta correctamente (y que los permisos son correctos cuando Hago un "netsh http urlacl show"), I * STILL * obtengo el mismo error. –

2

Después de medio dev días experimentando con la invocación netsh.exe desde un script de inicio elevada en vano, me di por vencido y terminó con el martillo grande y tomando la sugerencia inicial de Ryan de correr todo el rol de trabajo elevada :

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

Eso resolvió todos los problemas.

Para referencia, aquí es cómo me trató para permitir el registro HTTP para las cuentas de usuario no elevado (que en realidad nunca funcionó):

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

Y en el script de inicio (inicio \ Instalar.cmd en mi caso):

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

Esta es básicamente la solución que fue recomendado por las buenas personas que trabajan en AspNetWebApi (sólo una forma más corta de hacer lo que recomiendan here), pero desafortunadamente no funcionó para mí - Mientras el comando netsh se ejecutó correctamente y pude verificar que el urlacl en la URL en la que estoy alojado (en http: // +: 8080/api /) está permitido por \ Everyone, todavía recibía el mismo permiso error. Si alguien descubre cómo hacer que esto funcione cuando ejecuta el rol de trabajador no elevado, ¡por favor publíquelo!

+0

Ejecuté el script una vez en cmd, pero tuve que ejecutarlo como administrador: ¿con quién ejecuta su secuencia de comandos de inicio? Otra referencia [aquí] (http://www.asp.net/web-api/overview/hosting-aspnet-web-api/self-host-a-web-api) – Benjol

+0

Por defecto, Azure no ejecuta sus roles en cuentas elevadas, pero en cuentas de usuario bastante restringidas que no tienen nombres predecibles (son GUID que se crean cuando el controlador de fabric prepara la VM). Azure permite ejecutar scripts de inicio en una cuenta elevada (Admin), que es lo que hace el en mi código. Pero por alguna razón, el netsh.exe todavía no tuvo éxito al permitir el comando. Terminé teniendo que ejecutar ese rol completo (lo cual resolvió los problemas). –

+0

Vaya, lo siento, me salté el detalle 'Azure'! – Benjol

-1

Agregue la referencia 'System.ServiceModel' a su proyecto y con 'config.HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.Exact;' no obtiene la excepción de privilegios de administrador (acceso denegado).

+2

Un pequeño comentario por favor? – Zulu

Cuestiones relacionadas