将URL转换为控制器/操作对

时间:2017-04-13 12:40:41

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

在.Net MVC中,您将路由定义为RouteCollection。通过网址帮助程序方法,您可以轻松将controller + action + optional params转换为网址。

当.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列表,使用上述功能,您可以查看哪个控制器最受欢迎,或哪些操作等等。

2 个答案:

答案 0 :(得分:2)

您应该看看如何创建自己的MvcRouteHandler。这是MVC堆栈中的一点,路由引擎已经解析了URL以找到要调用的Controller和Action,然后它通过这个方法来获取实际的C#类和方法来调用。尚未授权甚至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();

答案 1 :(得分:1)

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