3

I wrote a very simple web app in Flask and am porting it to ASP.NET Framework. All the functionality is in JavaScript and HTMl, so the framework should just act as scaffolding. I've got almost everything ported over, except for what seems to be a routing issue. My site expects a string token variable to be appended to the URL, like so: www.mysite.com/token-string. For development, the URL is localhost:*****/string-token, with my Index.cshtml page being displayed as default.

When I pass the URL without the token it works fine and my index page loads. However I get a 404 when I try it with the token. I'm assuming it's identifying the token as a route and is trying to navigate to it? I'm not sure how to fix it. Here are the important parts of my code:

HomeController.cs:

public class HomeController : Controller { public ActionResult Index(string token) { return View(); } } 

RouteConfig.cs: NB: I've not changed this, not sure what to do with it.

public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } 

It's quite important that the token is passed in the way it is, rather than as a ? query parameter or anything like that. Additionally, the C# index view doesn't really need to do anything with the token - it gets extracted by the JavaScript.

Any advice is most welcome. Thanks.

4
  • You need to use www.mysite.com/?token='token-string' to use token string with default route, thus define a route which expects token parameter (url: "{controller}/{action}/{token}") where token is a required parameter. Commented Jun 19, 2017 at 9:25
  • @TetsuyaYamamoto Is that the only way to do this? I did state in my question that it really does have to be in the format of www.mysite.com/string-token Commented Jun 19, 2017 at 9:26
  • In MVC 5 you can use attribute routing with route [Route("~/{token?}")] on your Index action method, which results in www.mysite.com/string-token. Or define Index action method: url: "{token}" (with default route controller = "Home", action = "Index", token = UrlParameter.Optional). Commented Jun 19, 2017 at 9:30
  • @TetsuyaYamamoto thanks, that did it - if you put it into an answer (the other two didn't work) I can accept :) Commented Jun 19, 2017 at 9:40

3 Answers 3

2

Each segment (i.e. {controller}) in the route is a variable, and in the default route makes them all optional. Therefore, your default route is matching the request www.mysite.com/token-string.

What you need to do is insert a route that has a constraint to only match URLs with your token. Assuming your token is a GUID, you could use a regex route constraint as follows:

public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "TokenRoute", url: "{token}", defaults: new { controller = "Home", action = "Index" }, constraints: new { token = @"^[0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12}$" } ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } 

If your token is not a GUID, you could either use a different regex or implement IRouteConstraint to ensure the route only matches your tokens. The logic you use could be as simple as a == statement (as shown) or more complex (such as a database lookup).

public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "TokenRoute", url: "{token}", defaults: new { controller = "Home", action = "Index" }, constraints: new { token = new TokenConstraint() } ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } public class TokenConstraint : IRouteConstraint { public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { if ((string)values[parameterName] == "MyToken") { return true; } return false; } } 

Note that you should use the route value key {token} in the url: parameter to match the action method parameter name token.

public ActionResult Index(string token) { return View(); } 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks very much, excellent answer - I also very much appreciate the additional info about constraining the type of string which is allowed in different ways.
0

I guess you could try changing the default route to include token instead of id as shown below.

routes.MapRoute( name: "Default", url: "{controller}/{action}/{token}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); 

1 Comment

Unfortunately this did not work for me - I managed to get it working using the url as url: {token}
0

The default Route pattern which you have expects the parameter with name as 'id'

Either add (or modify the default route) like below route pattern

routes.MapRoute( name: "AnotherRoute", //your desired route name url: "{controller}/{action}/{token-string}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); 

1 Comment

Unfortunately this did not work for me - I managed to get it working using the url as url: {token}

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.