2012-04-04 11 views
13

W poniższym kodzie czekam na każde połączenie z portem 8080.Mapowanie URL za pomocą 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(); 
    } 
} 

Czy możliwe jest odwzorowanie określonych wzorców adresów URL na różne zachowania? Chcę osiągnąć serwera REST stylu czyli wezwanie do localhost: 8080/osoba/1 rozpocznie getPersonHandler (int)

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

Składnia Mapping jest tylko moja własna życzeniowe analogia do bibliotek JAX-RS, że wiedzieć. Chciałbym zrobić to samo w C# (pulpitu C#, nie ASP)

+1

Czy naprawdę trzeba odkrywać nowe koło? Web API w ASP.NET MVC 4 może to zrobić. –

+0

Potrzebuję samodzielnej aplikacji. – emesx

+4

FYI ASP.NET Web API może być hostowany samodzielnie (bez usług IIS) – dcstraw

Odpowiedz

14

można uzyskać podobny efekt bez atrybutów

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

Wykorzystanie byłoby:

http://localhost:8080/getPersonHandler/333 

Jeśli naprawdę aby móc korzystać z atrybutów następnie

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

następnie można użyć jako http://localhost:8080/Person/333 i twoi definicje byłoby

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

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

co to jest @ rodzaj nazwy zmiennej? – emesx

+2

ponieważ 'params' jest zastrzeżonym słowem w języku C# Użyłem' @params' –

+1

Nie wiedziałem, że możesz użyć '@ 'w nazwach zmiennych, dziękuję. Podoba mi się ta odpowiedź. Dziękuję Ci bardzo. – emesx

4

Jeśli pracujesz w .NET 4.0 lub wyższy i szukasz pre-istniejącego rozwiązania serwerów REST, które można podłączyć do (co brzmi jak Ty), może chcesz sprawdzić Grapevine. Możesz go pobrać za pomocą NuGet, a project wiki ma dużo przykładowego kodu. Co więcej, jest to open source, więc jeśli chcesz tylko zobaczyć, jak można to zrobić, zobaczysz tam cały kod źródłowy.

Możesz filtrować żądania według informacji o ścieżce (za pomocą wyrażeń regularnych) i żądać metod (GET, POST itp.).

Jestem autorem projektu i miałem podobną potrzebę jak ta, którą opisałeś. Korzystając z zasobów, które znalazłem tu i gdzie indziej, zbudowałem Grapevine, tak, żebym miał rozwiązanie w mojej tylnej kieszeni, kiedy będę potrzebował go ponownie (DRY).

+0

Wow, to niesamowite, dzięki! – Luke

Powiązane problemy