使用C#HttpListener进行URL映射

eme*_*esx 16 c# http url-mapping

在下面的代码中,我正在等待对8080端口的任何调用.

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

是否可以将特定的URL模式映射到不同的行为?我想实现一个REST风格的服务器,即调用localhost:8080/person/1将启动getPersonH​​andler(int)

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

Mapping我知道,语法只是我对JAX-RS库的一厢情愿.我想在C#中做同样的事情(桌面C#,而不是asp)

L.B*_*L.B 18

没有属性,您可以获得类似的效果

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);
    });
Run Code Online (Sandbox Code Playgroud)

用法是:

http://localhost:8080/getPersonHandler/333
Run Code Online (Sandbox Code Playgroud)

如果你真的想使用属性那么

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);
    });
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用as 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);
}
Run Code Online (Sandbox Code Playgroud)

  • 因为`params`是c#中的保留字,我使用`@params` (2认同)
  • @elmes`ctx.Request.HttpMethod` (2认同)

Sco*_*fen 6

如果您使用的是.NET 4.0或更高版本,并且正在寻找可以插入的预先存在的REST服务器解决方案(听起来就像这样),您可能需要查看Grapevine.您可以使用NuGet获取它,项目维基有很多示例代码.另外,它是开源的,所以如果你只是想看看它是如何实现的,你可以在那里看到所有的源代码.

您可以按路径信息(使用正则表达式)和请求方法(GET,POST等)过滤请求.

我是项目作者,我和你描述的那个人有类似的需求.使用我在这里和其他地方找到的资源,我建立了Grapevine,这样每当我再次需要时,我就可以在后面的口袋中找到解决方案(DRY).