2012-04-04 2 views
13

В приведенном ниже коде я жду любого вызова порта 8080.URL-адрес сопоставления с 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(); 
    } 
} 

Возможно ли сопоставить определенные шаблоны URL с различным поведением? Я хочу, чтобы достичь серверов REST-стиль, т.е. вызова локального хоста: 8080/человек/1 запустят getPersonHandler (целое)

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

Синтаксис Mapping только моя собственная желаемая за действительной аналогию библиотеки JAX-RS, что я знать. Я хотел бы сделать то же самое в C# (рабочий стол C#, не осины)

+1

Вам действительно нужно изобретать велосипед? Веб-API в ASP.NET MVC 4 может это сделать. –

+0

Мне нужно отдельное приложение. – emesx

+4

Веб-API FYI ASP.NET Web может быть самостоятельным (без IIS) – dcstraw

ответ

14

Вы можете получить подобный эффект без признаков

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

Usage будет:

http://localhost:8080/getPersonHandler/333 

если вы на самом деле хотим использовать атрибуты затем

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

затем вы можете использовать как http://localhost:8080/Person/333 и ваши определения будут

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

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

что это такое @ param имя переменной? – emesx

+2

так как 'params' зарезервировано слово в C# Я использовал' @ params' –

+1

Я не знал, что вы можете использовать '@' в именах переменных, спасибо. Мне нравится этот ответ. Большое спасибо. – emesx

4

Если вы работаете в .NET 4.0 или выше, и ищете предварительно существующее решение REST сервера, который можно подключить к (что это звучит, как вы), вы можете проверить Grapevine. Вы можете получить его с помощью NuGet, и у project wiki есть много примеров кода. Кроме того, это с открытым исходным кодом, поэтому, если вы просто хотите посмотреть, как это можно сделать, вы можете увидеть весь исходный код.

Вы можете фильтровать запросы по информации о пути (используя регулярные выражения) и методы запроса (GET, POST и т. Д.).

Я автор проекта, и у меня была такая же потребность, как и описанная вами. Используя ресурсы, которые я нашел здесь и где-то еще, я построил Grapevine, чтобы у меня было решение в моем заднем кармане, когда мне это было нужно снова (DRY).

+0

wow это потрясающе, спасибо! – Luke