寻找C#URL路由器,但不寻找HTTP

时间:2016-05-06 10:50:56

标签: c# url-routing mqtt

我正在寻找一个C#URL路由器组件。非常经典的东西,采用/resources/:id/stuff之类的输入字符串并调用适当的方法。类似于默认的ASP.net路由或RestfullRouting。 但是,我没有使用HTTP,我不想要一个完整的HTTP堆栈/框架。我正在寻找一些轻松的路由我的MQTT消息。 你知道这个组件是否存在吗?

2 个答案:

答案 0 :(得分: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匹配。 / p>

要像这样使用:

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

这将生成一个{ "id" = "42" }的字典,您可以随意使用它。

答案 1 :(得分: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");
    }
}

可以这样使用:

var router = new UriRouter();

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

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

这将在标准输出上打印42 - abcd