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