2012-04-04 21 views
13

Trong mã bên dưới, tôi đang chờ mọi cuộc gọi đến cổng 8080.Ánh xạ URL với 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(); 
    } 
} 

Có thể ánh xạ các mẫu URL cụ thể cho hành vi khác nhau không? Tôi muốn đạt được một máy chủ kiểu REST tức là một lời kêu gọi localhost: 8080/người/1 sẽ ra mắt getPersonHandler (int)

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

Cú pháp Mapping chỉ là suy mơ của riêng tôi để JAX-RS thư viện mà tôi biết. Tôi muốn làm điều tương tự trong C# (máy tính để bàn C#, không asp)

+1

Bạn có thực sự cần phải tái tạo lại bánh xe không? Web API trong ASP.NET MVC 4 có thể làm điều này. –

+0

Tôi cần một ứng dụng độc lập. – emesx

+4

API Web FYI ASP.NET có thể tự lưu trữ (không có IIS) – dcstraw

Trả lời

14

Bạn có thể có được một hiệu ứng tương tự mà không thuộc tính

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

Cách sử dụng sẽ là:

http://localhost:8080/getPersonHandler/333 

nếu bạn thực sự muốn sử dụng Thuộc tính sau đó

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

Sau đó, bạn có thể sử dụng làm http://localhost:8080/Person/333 và định nghĩa của bạn sẽ là

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

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

đây là gì @ loại param của tên biến? – emesx

+2

vì 'params' là từ dành riêng trong C# Tôi đã sử dụng' @ params' –

+1

Tôi không biết bạn có thể sử dụng '@' trong tên biến, cảm ơn. Tôi thích câu trả lời này. Cảm ơn nhiều. – emesx

4

Nếu bạn đang làm việc trong .NET 4.0 hoặc cao hơn và tìm kiếm một giải pháp máy chủ REST của tồn tại trước đó mà bạn có thể cắm vào (mà có vẻ như bạn đang có), bạn có thể muốn kiểm tra Grapevine. Bạn có thể sử dụng NuGet và project wiki có nhiều mã mẫu. Thêm vào đó, nó là mã nguồn mở, vì vậy nếu bạn chỉ muốn xem nó có thể được hoàn thành như thế nào, bạn có thể thấy tất cả mã nguồn ở đó.

Bạn có thể lọc yêu cầu theo thông tin đường dẫn (sử dụng cụm từ thông dụng) và phương thức yêu cầu (GET, POST, v.v.).

Tôi là tác giả của dự án và tôi có nhu cầu tương tự như mô tả bạn đã mô tả. Sử dụng tài nguyên tôi tìm thấy ở đây và ở nơi khác, tôi đã xây dựng Grapevine để tôi sẽ có một giải pháp trong túi sau của tôi bất cứ khi nào tôi cần nó một lần nữa (DRY).

+0

wow thật tuyệt vời, cảm ơn! – Luke