Check if the request URL is in the route table

I want to check if the URL is part of the routes defined in Global.asax . This is what I have:

 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; } } 

The problem is that I cannot extract the URL from the route. What do i need to change?

+6
source share
4 answers

Here is what I did:

 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 } } 

It is hacked, but works in 3 lines.

0
source

The problem is that I cannot extract the URL from the route.

I disagree. The problem is what you expect to pull the URLs from the route table and compare them from the outside. In addition, it is unclear what you hope to get by doing this.

Routing compares an incoming request with business logic to determine if it matches. This is the goal of the route . Moving the matching logic outside the route is not a valid test because you are not testing the business logic implemented by the route.

Not to mention that it’s somewhat assumed that the route can only match the URL, and nothing else in the request, for example, the values ​​of form messages or cookies. Although the built-in routing function matches only URLs, there is nothing stopping you from making a restriction or custom route that meets other criteria.

So, in short, you need to write unit tests for the business logic in your routes. Any logic that occurs outside of your route configuration must be separately tested.

There is a great article from Brad Wilson (albeit a bit dated) that demonstrates how to unit test your routes. I updated the code to work with MVC 5 - here is a working demo using the code below.

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

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; } } 

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; } } 

With this in mind, back to your original question.

How to determine if a url is in a route table?

The question is a bit presumptive. As others have pointed out, the route table does not contain URLs; it contains business logic. A more correct way to express a question would be:

How to determine if the incoming URL matches any route in the route table?

Then you are on your way.

To do this, you need to follow the GetRouteData business logic in the route collection. This will execute the GetRouteData method for each route until the first of them returns a RouteData object instead of null . If none of them returns a RouteData object (i.e., all routes return null ), this means that none of the routes matches the query.

In other words, a null result from GetRouteData indicates that none of the routes matched the query. The RouteData object indicates that one of the routes is consistent and it provides the necessary route data (controller, action, etc.) so that the MVC matches the action method.

So, to just check if the URL matches the route, you just need to determine if the result of the operation is 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); } 

Note also that route generation is a separate task from matching incoming routes. You can generate outgoing URLs from routes, but it uses a completely different set of business logic than matching inbound routes. This outgoing URL logic can (and should) be tested separately from the incoming URL logic, as shown above.

+7
source

You can try checking the current context of the route table.

 var contextBase = HttpContext.Current.Request.RequestContext.HttpContext; var data = RouteTable.Routes.GetRouteData(contextBase); if (data != null) { //Route exists } 

Using the above as a basis for creating a service

 public interface IRouteInspector { bool RequestIsInRoutes(); } public interface IHttpContextAccessor { HttpContextBase HttpContext { get; } } public interface IRouteTable { RouteCollection Routes { get; } } public class RouteInspector : IRouteInspector { private IRouteTable routeTable; private IHttpContextAccessor contextBase; public RouteInspector(IRouteTable routeTable, IHttpContextAccessor contextBase) { this.routeTable = routeTable; this.contextBase = contextBase; } public bool RequestIsInRoutes() { if (routeTable.Routes.GetRouteData(contextBase.HttpContext) != null) { //Route exists return true; } return false; } } 

And here is a test class showing how it is used.

 [TestClass] public class RouteTableUnitTests : ControllerUnitTests { [TestMethod] public void Should_Get_Request_From_Route_Table() { //Arrange var contextBase = new Mock<IHttpContextAccessor>(); contextBase.Setup(m => m.HttpContext) .Returns(HttpContext.Current.Request.RequestContext.HttpContext); var routeTable = new Mock<IRouteTable>(); routeTable.Setup(m => m.Routes).Returns(RouteTable.Routes); var sut = new RouteInspector(routeTable.Object, contextBase.Object); //Act var actual = sut.RequestIsInRoutes(); //Assert Assert.IsTrue(actual); } } 

There is room for refactoring and improvements, but this is the beginning.

+2
source

I don’t know if this is what you want, this is the requested route, if so, you can get it from the current request:

 var route = HttpContext.Current.Request.RequestContext.RouteData.Route; 
+1
source

All Articles