Routing legacy queries with and without query

(Before launch: I know this and this . I would like to find a more concise solution - if possible - for a slightly more specific problem)

I am rewriting an old Webforms application in MVC. As usual, no permalinks should be broken.

I use standard routes {controller}/{action}/{id} . Usually for old paths SomePage.aspx?ID=xxx , and I have one special case when Foo.aspx is the Bar list (new URL: / Bar or / Bar / Index ) and also Foo.aspx?ID=xxx - this is the Bar part (new URL: / Bar / View / xxx )

One possible workaround is to add the following value before the MapRoute default MapRoute :

 routes.MapRoute("Bar View", "Foo.aspx", new { controller = "Bar", action = "View" }); 

And then defining the appropriate action in BarController:

 public ActionResult View(int? id) { if (id == null) return RedirectToAction("Index"); return View(); } 

There are two problems with this:

  • Now, if I create ActionLink, it uses an obsolete format
  • I would like to handle this on routes; making the identifier zero and redirecting to the controller is simply wrong

I am fine with manually matching outdated URLs (I don't need a general solution, but only about 8 pages)

This is a new project, so I'm not attached to anything.

+6
source share
2 answers

I was able to solve this problem based on Dangerous' idea plus a limitation based on this answer .

My new route table:

 routes.MapRoute("Bar", "Bar/{action}/{id}", new { controller = "Bar", action = "Index", id = UrlParameter.Optional }); routes.MapRoute("Bar View", "Foo.aspx", new {controller = "Bar", action = "View"}, new {id = new QueryStringConstraint()}); routes.MapRoute("Bar Index", "Foo.aspx", new { controller = "Bar", action = "Index" }); routes.MapRoute("Default", /*...*/); 

And QueryStringConstraint couldn't be simpler:

 public class QueryStringConstraint : IRouteConstraint { public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { return httpContext.Request.QueryString.AllKeys .Contains(parameterName, StringComparer.InvariantCultureIgnoreCase); } } 
+3
source

I believe that if you specify the following routes:

 routes.MapRoute( null, "Bar/{action}/{id}", new { controller = "Bar", action = "View", id = UrlParameter.Optional }, new { action = "Index|Next" } //contrain route from being used by other action (if required) ); routes.MapRoute( null, "Foo.aspx/{id}", new { controller = "Bar", action = "View", id = UrlParameter.Optional } ); //specify other routes here for the other legacy routes you have. 

Then this should solve your first problem. If the user specifies Foo.aspx in the URL, they will be migrated to the View action.

If the action link:

 @Html.ActionLink("Click me", "Index", "Bar") 

then the first route will be used (as it matters).

However, I could not figure out how to indicate if Foo.aspx?id=... then go to one else route if Foo.aspx is specified and then go to another route. So I would check if id is equal in action. However, if you find out, I would love to know.

Hope this helps.

+2
source

Source: https://habr.com/ru/post/907781/


All Articles