2012-04-04 20 views
13

En el siguiente código estoy esperando cualquier llamada al puerto 8080.Asignación de URL con C# HttpListener

static void Main() 
{ 
    HttpListener listener = new HttpListener(); 
    listener.Prefixes.Add("http://*:8080/"); 
    listener.Start(); 
    while(isRunning) 
    { 
    HttpListenerContext ctx = listener.GetContext(); 
    new Thread(new Worker(ctx).ProcessRequest).Start(); 
    } 
} 

¿Es posible asignar patrones específicos de URL a comportamientos diferentes? Quiero conseguir un servidor de estilo REST es decir, una llamada a localhost: 8080/persona/1 lanzará getPersonHandler (int)

[Mapping("*:8080/person/$id")] 
public void getPersonHandler(int id){...} 

La sintaxis Mapping es sólo mi propia analogía deseosa de bibliotecas JAX-RS que yo saber. Me gustaría hacer lo mismo en C# (escritorio C#, no asp)

+1

¿Realmente necesita reinventar la rueda? La API web en ASP.NET MVC 4 puede hacer esto. –

+0

Necesito una aplicación independiente. – emesx

+4

FYI ASP.NET Web API puede ser alojada por sí misma (sin IIS) – dcstraw

Respuesta

14

, usted puede obtener un efecto similar sin atributos

HttpListener listener = new HttpListener(); 
listener.Prefixes.Add("http://*:8080/"); 
listener.Start(); 
while (true) 
{ 
    HttpListenerContext ctx = listener.GetContext(); 
    ThreadPool.QueueUserWorkItem((_) => 
    { 
     string methodName = ctx.Request.Url.Segments[1].Replace("/", ""); 
     string[] strParams = ctx.Request.Url 
           .Segments 
           .Skip(2) 
           .Select(s=>s.Replace("/","")) 
           .ToArray(); 


     var method = this.GetType().GetMethod(methodName); 
     object[] @params = method.GetParameters() 
          .Select((p, i) => Convert.ChangeType(strParams[i], p.ParameterType)) 
          .ToArray(); 

     object ret = method.Invoke(this, @params); 
     string retstr = JsonConvert.SerializeObject(ret); 
    }); 

uso sería:

http://localhost:8080/getPersonHandler/333 

si realmente quieren utilizar atributos continuación

HttpListener listener = new HttpListener(); 
listener.Prefixes.Add("http://*:8080/"); 
listener.Start(); 
while (true) 
{ 
    HttpListenerContext ctx = listener.GetContext(); 
    ThreadPool.QueueUserWorkItem((_) => 
    { 
     string methodName = ctx.Request.Url.Segments[1].Replace("/", ""); 
     string[] strParams = ctx.Request.Url 
           .Segments 
           .Skip(2) 
           .Select(s=>s.Replace("/","")) 
           .ToArray(); 

     var method = this.GetType() 
          .GetMethods() 
          .Where(mi => mi.GetCustomAttributes(true).Any(attr => attr is Mapping && ((Mapping)attr).Map == methodName)) 
          .First(); 

     object[] @params = method.GetParameters() 
          .Select((p, i) => Convert.ChangeType(strParams[i], p.ParameterType)) 
          .ToArray(); 

     object ret = method.Invoke(this, @params); 
     string retstr = JsonConvert.SerializeObject(ret); 
    }); 
} 

a continuación, se puede utilizar como http://localhost:8080/Person/333 y sus definiciones serían

class Mapping : Attribute 
{ 
    public string Map; 
    public Mapping(string s) 
    { 
     Map = s; 
    } 
} 

[Mapping("Person")] 
public void getPersonHandler(int id) 
{ 
    Console.WriteLine("<<<<" + id); 
} 
+0

¿Qué es esto? param tipo de nombre de variable? – emesx

+2

ya que 'params' es palabra reservada en C# He usado' @ params' –

+1

No sabía que puede usar '@' en nombres de variables, gracias. Me gusta esta respuesta Muchas gracias. – emesx

4

Si está trabajando en .NET 4.0 o superior y en busca de una solución de servidor REST pre-existente que se puede conectar a (que suena como si estuviera), es posible que desee comprobar hacia fuera Grapevine. Puedes obtenerlo usando NuGet, y el project wiki tiene un montón de código de muestra. Además, es de código abierto, por lo que si solo quieres ver cómo se puede lograr, puedes ver todo el código fuente allí.

Puede filtrar las solicitudes por información de ruta (usando expresiones regulares) y métodos de solicitud (GET, POST, etc.).

Soy el autor del proyecto y tenía una necesidad similar a la que describió. Utilizando los recursos que encontré aquí y en otros lugares, construí Grapevine para tener una solución en mi bolsillo trasero cada vez que la necesitaba de nuevo (DRY).

+0

wow es increíble, gracias! – Luke