正在寻找一个C#URL路由器,但不是HTTP
我正在寻找一个C#URL路由器组件。非常经典的东西,获取输入字符串,如正在寻找一个C#URL路由器,但不是HTTP,c#,url-routing,mqtt,C#,Url Routing,Mqtt,我正在寻找一个C#URL路由器组件。非常经典的东西,获取输入字符串,如/resources/:id/stuff,并调用适当的方法。类似于默认ASP.net路由或。 但是,我不使用HTTP,也不想要完整的HTTP堆栈/框架。我正在寻找一些轻路由我的MQTT消息。 您知道是否存在这样的组件吗?以下非优化、非真正防御性编码的代码针对路由解析URI: public class UriRouteParser { private readonly string[] _routes; pub
/resources/:id/stuff
,并调用适当的方法。类似于默认ASP.net路由或。
但是,我不使用HTTP,也不想要完整的HTTP堆栈/框架。我正在寻找一些轻路由我的MQTT消息。
您知道是否存在这样的组件吗?以下非优化、非真正防御性编码的代码针对路由解析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;
}
}
这将产生一个
{“id”=“42”}
字典,您可以随意使用它。我很快改变了@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
。对于不熟悉RestfulRouting的人,您能确切解释一下它的功能吗?您能解释一下如何从字符串调用方法吗?您只是希望通过/
分割并获取相对URI的部分吗?此外,对库的请求与堆栈溢出无关,因此最好只描述如何准确地执行您想要执行的操作。它将根据路由调用一个方法。一个非常简单的路由器可以通过/
进行拆分,并使用几个交换机
块。更高级的路由器将提供一个简单的API和一些解析方法。这在HTTP框架(Rails、Express、CakePHP…)中非常常见。您现在如何实现mqtt?是的,我知道web应用程序中的路由是什么,只是不清楚您到底在寻找什么功能。@montewhizdoh:我使用。非常感谢。我为您的解决方案添加了委托,这正是我所需要的:-)可以应用的第一个优化是在构造函数中预构建正则表达式,而不是每个方法调用。您可能还需要添加一些参数检查,例如具有重复变量名或根本没有变量的路由。是的,我只更新了一次代码以构建正则表达式。
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");