2016-05-06 5 views
3

私はC#URLルーターコンポーネントを探しています。非常に古典的なもの、/resources/:id/stuffなどの入力文字列を取り、適切なメソッドを呼び出します。既定のASP.netルーティングまたはRestfullRoutingに似た何か。 しかし、私はHTTPを使用していないので、私は完全なHTTPスタック/フレームワークを望んでいません。私はMQTTメッセージをルーティングするために何か光を探しています。 そのようなコンポーネントが存在するかどうか知っていますか?C#URLルーターを探しますが、HTTP用ではない

+0

RestfulRoutingに慣れていない人には、それが何をしているのか正確に説明できますか?文字列からメソッドを呼び出す方法を説明できますか?単純に '/'で分割して、相対URIの部分を取得しようとしていますか?また、ライブラリのリクエストはスタックオーバーフローの話題になっているので、正確にやりたいことをどうやって行うのかを説明するだけです。 – CodeCaster

+0

ルータは文字列ルートを入力とコンテキストとして受け取ります。それはルートに応じてメソッドを呼び出します。非常に単純なルータは '/'で分割し、いくつかの 'switch'ブロックを使用することができます。より高度なルータは、シンプルなAPIといくつかの解析メソッドを提供します。 HTTPフレームワーク(Rails、Express、CakePHP ...)では非常に一般的です。 – yellowiscool

+0

mqtt実装はどうやってやっていますか? – montewhizdoh

答えて

1

非最適化され、次のではなく、実際に防御的にコード化されたコードは、ルートに対するURIを解析します

public class UriRouteParser 
{ 
    private readonly string[] _routes; 

    public UriRouteParser(IEnumerable<string> routes) 
    { 
     _routes = routes.ToArray(); 
    } 

    public Dictionary<string, string> GetRouteValues(string uri) 
    { 
     foreach (var route in _routes) 
     { 
      // Build RegEx from route (:foo to named group (?<foo>[a-z0-9]+)). 
      var routeFormat = new Regex("(:([a-z]+))\\b").Replace(route, "(?<$2>[a-z0-9]+)"); 

      // Match uri parameter to that regex. 
      var routeRegEx = new Regex(routeFormat); 

      var match = routeRegEx.Match(uri); 

      if (!match.Success) 
      { 
       continue; 
      } 

      // Obtain named groups. 
      var result = routeRegEx.GetGroupNames().Skip(1) // Skip the "0" group 
            .Where(g => match.Groups[g].Success && match.Groups[g].Captures.Count > 0) 
            .ToDictionary(groupName => groupName, groupName => match.Groups[groupName].Value); 
      return result; 
     } 

     // No match found 
     return null; 
    } 
} 

これは、入力(ルートとURIの両方)についていくつかの前提条件になりますが、基本的には:fooパラメータ名を選びますそれらの名前付きキャプチャグループを作成し、入力URIと照合します。このように使用することが

var parser = new UriRouteParser(new []{ "/resources/:id/stuff" }); 
var routeValues = parser.GetRouteValues("/resources/42/stuff"); 

これは、あなたが好きなようにあなたがして使用できる、{ "id" = "42" }の辞書を生成します。

+0

ありがとうございます。代理人をあなたのソリューションに追加しました。それは私が必要としていたものです:-) – yellowiscool

1

すぐに@ CodeCasterのソリューションを変更して、代理人をアタッチして呼び出すようにしました。このように使用することができます

public class UriRouter 
{ 
    // Delegate with a context object and the route parameters as parameters 
    public delegate void MethodDelegate(object context, Dictionary<string, string> parameters); 

    // Internal class storage for route definitions 
    protected class RouteDefinition 
    { 
     public MethodDelegate Method; 
     public string RoutePath; 
     public Regex RouteRegEx; 

     public RouteDefinition(string route, MethodDelegate method) 
     { 
      RoutePath = route; 
      Method = method; 

      // Build RegEx from route (:foo to named group (?<foo>[a-z0-9]+)). 
      var routeFormat = new Regex("(:([a-z]+))\\b").Replace(route, "(?<$2>[a-z0-9]+)"); 

      // Build the match uri parameter to that regex. 
      RouteRegEx = new Regex(routeFormat); 
     } 
    } 

    private readonly List<RouteDefinition> _routes; 

    public UriRouter() 
    { 
     _routes = new List<RouteDefinition>(); 
    } 

    public void DefineRoute(string route, MethodDelegate method) 
    { 
     _routes.Add(new RouteDefinition(route, method)); 
    } 

    public void Route(string uri, object context) 
    { 
     foreach (var route in _routes) 
     { 
      // Execute the regex to check whether the uri correspond to the route 
      var match = route.RouteRegEx.Match(uri); 

      if (!match.Success) 
      { 
       continue; 
      } 

      // Obtain named groups. 
      var result = route.RouteRegEx.GetGroupNames().Skip(1) // Skip the "0" group 
            .Where(g => match.Groups[g].Success && match.Groups[g].Captures.Count > 0) 
            .ToDictionary(groupName => groupName, groupName => match.Groups[groupName].Value); 

      // Invoke the method 
      route.Method.Invoke(context, result); 

      // Only the first match is executed 
      return; 
     } 

     // No match found 
     throw new Exception("No match found"); 
    } 
} 

:標準出力に42 - abcdを印刷します

var router = new UriRouter(); 

router.DefineRoute("/resources/:id/stuff", 
    (context, parameters) => Console.WriteLine(parameters["id"] + " - " + context)); 

router.Route("/resources/42/stuff", "abcd"); 

+0

最初の最適化は、各メソッド呼び出しとは対照的にコンストラクタで正規表現をあらかじめ構築することです。重複する変数名を持つルートや変数をまったく持たないルートなど、いくつかのパラメータチェックを追加することもできます。 – CodeCaster

+0

はい、正規表現を一度しか作成しないようにコードを更新しました。 – yellowiscool

関連する問題