将 URL 变成控制器/动作对
Turning URL into controller / action pair
在 .Net MVC 中,您将路由定义到 RouteCollection
中。 URL 辅助方法可以轻松地将 controller
+ action
+ optional params
转换为 URL。
当.Net MVC处理来自客户端浏览器的请求时,它清楚地将这个URL映射到右边的controller
+ action
,以执行适当的命令。
但是,我看不到以编程方式即时访问此路由的方法,这样我就可以将完全限定的 URL(或 10k+ URLs 的列表)转换为它是路由组件。
有谁知道你会怎么转,比如下面的字符串input:
""
进入如下输出:
{
controller: "questions",
action: "view",
id: 2342325,
seoText: "c-sharp-net-mvc-turning-url-into-controller-action-pair"
}
鉴于此映射显然是由 .Net 完成的,它是否暴露在任何地方?
为什么会有人想要这样做?
假设您有一个您知道已被访问的 URL 的列表,大多数本质上是动态的,例如 whosebug.com/questions/2342325/c-sharp-net-mvc-turning-url-into-controller-action-pair
,并且您想要计算出哪些实际端点/操作/控制器是以编程方式被命中(不太关心传递的实际数据)。
你 可以 手写代码映射,这样你就知道 /questions/{id}/{text}
-> controller: questions, action: question
,但这不是面向未来的,也不是很有趣,并依赖于文本操作/处理。
给定一个路由字典和一个 URL 的列表,具有上述功能,您可以查看哪些控制器被击中最多,或者哪些动作等。
您应该看看创建自己的 MvcRouteHandler。这是 MVC 堆栈中的一点,Route Engine 已经解析了 URL 以找到要调用的 Controller 和 Action,然后它通过此方法获取实际的 C# class 和方法来调用。尚未应用授权甚至 HTTP Verb,因此您将看到对您的应用程序进行的每个调用。
public class CustomRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext context)
{
var controller = context.RouteData.Values["controller"];
var action = context.RouteData.Values["action"];
// Do whatever logging you want with this data, maybe grab the other params too.
return base.GetHttpHandler(context);
}
}
这可以很容易地在您设置路由的地方注册。
routes.MapRoute("Home", "{controller}/{action}", new
{
controller = "Home",
action = "Index"
})
.RouteHandler = new CustomRouteHandler();
看起来唯一的方法是创建一个虚拟的 HTTP 上下文,类似于单元测试路由的方式。遗憾的是 MVC 没有提供对此的更好访问,因为它在每个请求上都是 运行,而不是将它包装在上下文对象中。
无论如何,这里有一个可行的解决方案,可以根据您的需要进行修改:
public class UrlToRouteMapper
{
public static RouteValueDictionary GetRouteDataFromURL(string absoluteURL)
{
var testUrl = "~" + new Uri(absoluteURL).AbsolutePath;
var context = new StubHttpContextForRouting(requestUrl: testUrl);
var routes = new System.Web.Routing.RouteCollection();
MvcApplication.RegisterRoutes(routes);
System.Web.Routing.RouteData routeData = routes.GetRouteData(context);
return routeData.Values;
}
public static string GetEndpointStringFromURL(string absoluteURL)
{
var routeData = GetRouteDataFromURL(absoluteURL);
return routeData["controller"] + "/" + routeData["action"];
}
}
public class StubHttpContextForRouting : HttpContextBase {
StubHttpRequestForRouting _request;
StubHttpResponseForRouting _response;
public StubHttpContextForRouting(string appPath = "/", string requestUrl = "~/") {
_request = new StubHttpRequestForRouting(appPath, requestUrl);
_response = new StubHttpResponseForRouting();
}
public override HttpRequestBase Request {
get { return _request; }
}
public override HttpResponseBase Response {
get { return _response; }
}
}
public class StubHttpRequestForRouting : HttpRequestBase {
string _appPath;
string _requestUrl;
public StubHttpRequestForRouting(string appPath, string requestUrl) {
_appPath = appPath;
_requestUrl = requestUrl;
}
public override string ApplicationPath {
get { return _appPath; }
}
public override string AppRelativeCurrentExecutionFilePath {
get { return _requestUrl; }
}
public override string PathInfo {
get { return ""; }
}
}
public class StubHttpResponseForRouting : HttpResponseBase {
public override string ApplyAppPathModifier(string virtualPath) {
return virtualPath;
}
}
在 .Net MVC 中,您将路由定义到 RouteCollection
中。 URL 辅助方法可以轻松地将 controller
+ action
+ optional params
转换为 URL。
当.Net MVC处理来自客户端浏览器的请求时,它清楚地将这个URL映射到右边的controller
+ action
,以执行适当的命令。
但是,我看不到以编程方式即时访问此路由的方法,这样我就可以将完全限定的 URL(或 10k+ URLs 的列表)转换为它是路由组件。
有谁知道你会怎么转,比如下面的字符串input:
""
进入如下输出:
{
controller: "questions",
action: "view",
id: 2342325,
seoText: "c-sharp-net-mvc-turning-url-into-controller-action-pair"
}
鉴于此映射显然是由 .Net 完成的,它是否暴露在任何地方?
为什么会有人想要这样做?
假设您有一个您知道已被访问的 URL 的列表,大多数本质上是动态的,例如 whosebug.com/questions/2342325/c-sharp-net-mvc-turning-url-into-controller-action-pair
,并且您想要计算出哪些实际端点/操作/控制器是以编程方式被命中(不太关心传递的实际数据)。
你 可以 手写代码映射,这样你就知道 /questions/{id}/{text}
-> controller: questions, action: question
,但这不是面向未来的,也不是很有趣,并依赖于文本操作/处理。
给定一个路由字典和一个 URL 的列表,具有上述功能,您可以查看哪些控制器被击中最多,或者哪些动作等。
您应该看看创建自己的 MvcRouteHandler。这是 MVC 堆栈中的一点,Route Engine 已经解析了 URL 以找到要调用的 Controller 和 Action,然后它通过此方法获取实际的 C# class 和方法来调用。尚未应用授权甚至 HTTP Verb,因此您将看到对您的应用程序进行的每个调用。
public class CustomRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext context)
{
var controller = context.RouteData.Values["controller"];
var action = context.RouteData.Values["action"];
// Do whatever logging you want with this data, maybe grab the other params too.
return base.GetHttpHandler(context);
}
}
这可以很容易地在您设置路由的地方注册。
routes.MapRoute("Home", "{controller}/{action}", new
{
controller = "Home",
action = "Index"
})
.RouteHandler = new CustomRouteHandler();
看起来唯一的方法是创建一个虚拟的 HTTP 上下文,类似于单元测试路由的方式。遗憾的是 MVC 没有提供对此的更好访问,因为它在每个请求上都是 运行,而不是将它包装在上下文对象中。
无论如何,这里有一个可行的解决方案,可以根据您的需要进行修改:
public class UrlToRouteMapper
{
public static RouteValueDictionary GetRouteDataFromURL(string absoluteURL)
{
var testUrl = "~" + new Uri(absoluteURL).AbsolutePath;
var context = new StubHttpContextForRouting(requestUrl: testUrl);
var routes = new System.Web.Routing.RouteCollection();
MvcApplication.RegisterRoutes(routes);
System.Web.Routing.RouteData routeData = routes.GetRouteData(context);
return routeData.Values;
}
public static string GetEndpointStringFromURL(string absoluteURL)
{
var routeData = GetRouteDataFromURL(absoluteURL);
return routeData["controller"] + "/" + routeData["action"];
}
}
public class StubHttpContextForRouting : HttpContextBase {
StubHttpRequestForRouting _request;
StubHttpResponseForRouting _response;
public StubHttpContextForRouting(string appPath = "/", string requestUrl = "~/") {
_request = new StubHttpRequestForRouting(appPath, requestUrl);
_response = new StubHttpResponseForRouting();
}
public override HttpRequestBase Request {
get { return _request; }
}
public override HttpResponseBase Response {
get { return _response; }
}
}
public class StubHttpRequestForRouting : HttpRequestBase {
string _appPath;
string _requestUrl;
public StubHttpRequestForRouting(string appPath, string requestUrl) {
_appPath = appPath;
_requestUrl = requestUrl;
}
public override string ApplicationPath {
get { return _appPath; }
}
public override string AppRelativeCurrentExecutionFilePath {
get { return _requestUrl; }
}
public override string PathInfo {
get { return ""; }
}
}
public class StubHttpResponseForRouting : HttpResponseBase {
public override string ApplyAppPathModifier(string virtualPath) {
return virtualPath;
}
}