【问题标题】:Turning URL into controller / action pair将 URL 变成控制器/动作对
【发布时间】:2017-04-13 12:40:40
【问题描述】:

在 .Net MVC 中,您将路由定义为 RouteCollection。 URL 帮助器方法可以轻松地将 controller + action + optional params 转换为 URL。

.Net MVC 处理来自客户端浏览器的请求时,它清楚地将这个 URL 映射到右边的controller + action,以执行相应的命令。

但是,我看不到以编程方式即时访问此路由的方法,因此我可以将完全限定的 URL(或 10k+ URL 的列表)转换为其路由组件。

有谁知道你会怎么转,例如,下面的字符串输入

"http://stackoverflow.com/questions/2342325/c-sharp-net-mvc-turning-url-into-controller-action-pair"

进入以下输出

{
   controller: "questions",
   action: "view",
   id: 2342325,
   seoText: "c-sharp-net-mvc-turning-url-into-controller-action-pair"
}

鉴于此映射显然是由 .Net 完成的,它是否暴露在任何地方?

为什么有人要这样做?

假设你有一个你知道已经被访问过的 URL 列表,本质上大多是动态的,例如 stackoverflow.com/questions/2342325/c-sharp-net-mvc-turning-url-into-controller-action-pair,并且你想知道哪些实际的端点/动作/控制器正在以编程方式被命中(不太关心传递的实际数据)。

可以手动进行代码映射,这样您就知道/questions/{id}/{text} -> controller: questions, action: question,但这不是面向未来的,也不是很有趣,并且依赖于文本操作/处理。

给定一个路由字典和一个 URL 列表,使用上述功能,您可以查看哪些控制器最受打击,或者哪些操作等。

【问题讨论】:

  • 不清楚为什么要这样做,但您可以使用Uri uri = new Uri("http://stackoverflow.com/questions/ask"); 并检查其Segments 属性
  • @StephenMuecke - 在问题中添加了“为什么”。但我认为这些段只会告诉你 URL 段,而不关心被调用的实际控制器/动作。
  • 在您的示例中,Segments[0] 将返回“问题”,Segments[1] 将返回 "ask",但如果您没有为方法。
  • @StephenMuecke 我将更新示例,以便更清楚我的要求。
  • 您的要求在技术上不可行。 URL 仅与特定路由或路由集一起具有意义,这些路由或路由集决定了 URL 的解析方式以及初始化的控制器和操作。例如,我可以有一个将 URL“/foo/”映射到MyAwesomeController.MyAwesomeAction 的路由。在这种情况下,您绝对不可能只查看 URL 字符串并知道将调用什么控制器和操作。

标签: c# asp.net-mvc url-routing


【解决方案1】:

您应该看看创建自己的MvcRouteHandler。这是 MVC 堆栈中路由引擎已经解析 URL 以找到要调用的 Controller 和 Action 的点,然后通过此方法获取要调用的实际 C# 类和方法。尚未应用授权甚至 HTTP 动词,因此您将看到对您的应用程序进行的每个调用。

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();

【讨论】:

  • 我正在尝试将字符串输入 (URL) 转换为它的路由组件。如果我错了,请纠正我,但您的回答是假设有检查请求?想象一下,您有一个包含 10k 个 URL 的列表,并希望使用现有路由查看它们在当前应用程序中映射到哪些控制器/操作。抱歉,如果我的问题不清楚 - 欢迎编辑!
  • 那你的问题真的不清楚。您为什么要在 调用它之后检查 URL?这就是您利用 MVC 框架为您完成繁重工作的方式。
  • 因为我有一个 URL 列表,并且想弄清楚它们引用了哪些控制器和操作......这与在给定请求期间利用 MVC 无关,问题是是否有可能将字符串 URL 转换为操作/控制器。
  • 这是在同一个应用程序中吗?您可以尝试实例化您运行网站的路由器版本。您将遇到的问题是无法保证路线遵循{controller}/{action} 布局。可以设置一个{action}/foo/{controller}
  • 如果您要检查的是您的应用程序,并且您无法实例化路由引擎的实例,最简单的方法是实现我在答案中的内容,并编写一个控制台应用程序这将遍历您的 10k URL 并调用每个 URL,并在请求期间利用 MVC 来完成。
【解决方案2】:

看起来这样做的唯一方法是创建一个虚拟 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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多