测试请求的URL是否在Route表中

fre*_*hie 6 c# asp.net asp.net-mvc url-routing asp.net-mvc-routing

我想测试一个URL是否是在中定义的路由的一部分Global.asax.这就是我所拥有的:

var TheRequest = HttpContext.Current.Request.Url.AbsolutePath.ToString();
var TheRoutes = System.Web.Routing.RouteTable.Routes;

foreach (var TheRoute in TheRoutes)
{
    if (TheRequest  == TheRoute.Url) //problem here
    {
        RequestIsInRoutes = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是我无法从路由中提取URL.我需要改变什么?

Nig*_*888 8

问题是我无法从路由中提取URL.

我不同意.问题是您希望将URL拉出路由表并在外部进行比较.此外,目前还不清楚你希望通过这样做获得什么.

路由将传入请求与业务逻辑进行比较,以确定它是否匹配.这是路线的目的.将匹配逻辑移到路由之外不是有效测试,因为您没有测试路由实现的业务逻辑.

更不用说,假设路由只能匹配URL而不是请求中的任何其他内容(例如表单发布值或cookie),这有点推测.虽然内置路由功能仅匹配URL,但没有什么能阻止您制定符合其他条件的约束或自定义路由.

因此,简而言之,您需要为路由中的业务逻辑编写单元测试.在路由配置之外发生的任何逻辑都应单独进行单元测试.

Brad Wilson有一篇很棒的文章(虽然有点陈旧),演示了如何对你的路线进行单元测试.我已经更新了代码以使用MVC 5 - 这是一个使用下面代码的工作演示.

IncomingRouteTests.cs

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcRouteTesting;
using System.Web.Mvc;
using System.Web.Routing;

[TestClass]
public class IncomingRouteTests
{
    [TestMethod]
    public void RouteWithControllerNoActionNoId()
    {
        // Arrange
        var context = new StubHttpContextForRouting(requestUrl: "~/controller1");
        var routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);

        // Act
        RouteData routeData = routes.GetRouteData(context);

        // Assert
        Assert.IsNotNull(routeData);
        Assert.AreEqual("controller1", routeData.Values["controller"]);
        Assert.AreEqual("Index", routeData.Values["action"]);
        Assert.AreEqual(UrlParameter.Optional, routeData.Values["id"]);
    }

    [TestMethod]
    public void RouteWithControllerWithActionNoId()
    {
        // Arrange
        var context = new StubHttpContextForRouting(requestUrl: "~/controller1/action2");
        var routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);

        // Act
        RouteData routeData = routes.GetRouteData(context);

        // Assert
        Assert.IsNotNull(routeData);
        Assert.AreEqual("controller1", routeData.Values["controller"]);
        Assert.AreEqual("action2", routeData.Values["action"]);
        Assert.AreEqual(UrlParameter.Optional, routeData.Values["id"]);
    }

    [TestMethod]
    public void RouteWithControllerWithActionWithId()
    {
        // Arrange
        var context = new StubHttpContextForRouting(requestUrl: "~/controller1/action2/id3");
        var routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);

        // Act
        RouteData routeData = routes.GetRouteData(context);

        // Assert
        Assert.IsNotNull(routeData);
        Assert.AreEqual("controller1", routeData.Values["controller"]);
        Assert.AreEqual("action2", routeData.Values["action"]);
        Assert.AreEqual("id3", routeData.Values["id"]);
    }

    [TestMethod]
    public void RouteWithTooManySegments()
    {
        // Arrange
        var context = new StubHttpContextForRouting(requestUrl: "~/a/b/c/d");
        var routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);

        // Act
        RouteData routeData = routes.GetRouteData(context);

        // Assert
        Assert.IsNull(routeData);
    }

    [TestMethod]
    public void RouteForEmbeddedResource()
    {
        // Arrange
        var context = new StubHttpContextForRouting(requestUrl: "~/foo.axd/bar/baz/biff");
        var routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);

        // Act
        RouteData routeData = routes.GetRouteData(context);

        // Assert
        Assert.IsNotNull(routeData);
        Assert.IsInstanceOfType(routeData.RouteHandler, typeof(StopRoutingHandler));
    }
}
Run Code Online (Sandbox Code Playgroud)

OutgoingRouteTests.cs

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcRouteTesting;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

[TestClass]
public class OutgoingRouteTests
{
    [TestMethod]
    public void ActionWithAmbientControllerSpecificAction()
    {
        UrlHelper helper = GetUrlHelper();

        string url = helper.Action("action");

        Assert.AreEqual("/defaultcontroller/action", url);
    }

    [TestMethod]
    public void ActionWithSpecificControllerAndAction()
    {
        UrlHelper helper = GetUrlHelper();

        string url = helper.Action("action", "controller");

        Assert.AreEqual("/controller/action", url);
    }

    [TestMethod]
    public void ActionWithSpecificControllerActionAndId()
    {
        UrlHelper helper = GetUrlHelper();

        string url = helper.Action("action", "controller", new { id = 42 });

        Assert.AreEqual("/controller/action/42", url);
    }

    [TestMethod]
    public void RouteUrlWithAmbientValues()
    {
        UrlHelper helper = GetUrlHelper();

        string url = helper.RouteUrl(new { });

        Assert.AreEqual("/defaultcontroller/defaultaction", url);
    }

    [TestMethod]
    public void RouteUrlWithAmbientValuesInSubApplication()
    {
        UrlHelper helper = GetUrlHelper(appPath: "/subapp");

        string url = helper.RouteUrl(new { });

        Assert.AreEqual("/subapp/defaultcontroller/defaultaction", url);
    }

    [TestMethod]
    public void RouteUrlWithNewValuesOverridesAmbientValues()
    {
        UrlHelper helper = GetUrlHelper();

        string url = helper.RouteUrl(new
        {
            controller = "controller",
            action = "action"
        });

        Assert.AreEqual("/controller/action", url);
    }

    static UrlHelper GetUrlHelper(string appPath = "/", RouteCollection routes = null)
    {
        if (routes == null)
        {
            routes = new RouteCollection();
            RouteConfig.RegisterRoutes(routes);
        }

        HttpContextBase httpContext = new StubHttpContextForRouting(appPath);
        RouteData routeData = new RouteData();
        routeData.Values.Add("controller", "defaultcontroller");
        routeData.Values.Add("action", "defaultaction");
        RequestContext requestContext = new RequestContext(httpContext, routeData);
        UrlHelper helper = new UrlHelper(requestContext, routes);
        return helper;
    }
}
Run Code Online (Sandbox Code Playgroud)

Stubs.cs

using System;
using System.Collections.Specialized;
using System.Web;

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 override object GetService(Type serviceType)
    {
        return null;
    }
}

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 override NameValueCollection ServerVariables
    {
        get { return new NameValueCollection(); }
    }
}

public class StubHttpResponseForRouting : HttpResponseBase
{
    public override string ApplyAppPathModifier(string virtualPath)
    {
        return virtualPath;
    }
}
Run Code Online (Sandbox Code Playgroud)

有了这个,回到你原来的问题.

如何确定URL是否在路由表中?

这个问题有点推定.正如其他人所指出的那样,路由表不包含URL,它包含业务逻辑.一个更正确的方法来表达问题将是:

如何确定传入的URL是否与路由表中的任何路由匹配?

那你就在路上.

为此,您需要GetRouteData在路径集合中执行业务逻辑.这将GetRouteData在每个路由上执行该方法,直到它们中的第一个返回一个RouteData对象而不是null.如果它们都没有返回RouteData对象(即,所有路由都返回null),则表示没有路由匹配该请求.

换句话说,null结果GetRouteData表示没有路由匹配请求.一个RouteData对象表示其中一条路由匹配,并提供必要的路由数据(控制器,动作等),以使MVC与动作方法匹配.

因此,要简单地检查URL是否与路由匹配,您只需确定操作的结果是否正确null.

[TestMethod]
public void EnsureHomeAboutMatches()
{
    // Arrange
    var context = new StubHttpContextForRouting(requestUrl: "~/home/about");
    var routes = new RouteCollection();
    RouteConfig.RegisterRoutes(routes);

    // Act
    RouteData routeData = routes.GetRouteData(context);

    // Assert
    Assert.IsNotNull(routeData);
}
Run Code Online (Sandbox Code Playgroud)

另请注意,生成路由是与匹配传入路由的单独任务.您可以从路由生成传出URL,但它使用与匹配传入路由完全不同的业务逻辑集.这个传出的URL逻辑可以(并且应该)与传入的URL逻辑分开进行单元测试,如上所示.

  • 你知道..我希望堆栈溢出有一个选项,给你一些方法来奖励人们一次"FreakingAwesomeAnswers"..因为你先生..值得一个这个答案!但我所能做的就是+1 (3认同)

fre*_*hie 0

这就是我最终所做的:

string TheRequest = HttpContext.Current.Request.Url.AbsolutePath.ToString();

foreach (Route r in System.Web.Routing.RouteTable.Routes)
{
    if (("/" + r.Url) == TheRequest)
    {
        //the request is in the routes
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然很hacky,但是只需3行就可以了。