Donald Jansen Donald Jansen - 3 months ago 25
C# Question

MVC RedirectToAction not hiding parameters

I have the following action

public ActionResult TemplateBuilder(int id, int? processId) { }


And then I have the following

@Url.Action("TemplateBuilder","InspectionTemplate")/id/processId


The url then looks like:
InspectionTemplate/TemplateBuilder/1/2


But if I use

return RedirectToAction("TemplateBuilder","InspectionTemplate", new { id=1, processId = 2});


Then I get the following result:
InspectionTemplate/TemplateBuilder/1?processId=2


How can I fix that.

Here is my Routing

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");


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

routes.MapRoute(
name: "ProcessRoute",
url: "{controller}/{action}/{id}/{processId}",
defaults: new
{
controller = "InspectionTemplate",
action = "TemplateBuilder",
id = UrlParameter.Optional,
processId = UrlParameter.Optional
}
);

routes.MapRoute(
name: "DateRoute",
url: "{controller}/{action}/{year}/{month}/{day}",
defaults: new
{
controller = "Inspection",
action = "Assign",
year = UrlParameter.Optional,
month = UrlParameter.Optional,
day = UrlParameter.Optional
}
);


}

Answer

You have 3 issues with your route definitions

  1. Only the last parameter in a route definition can be marked with UrlParameter.Optional. If you were to provide only one, then the routing engine has no way of knowing which parameter should be bound so the value(s) would be added as query string parameters).
  2. The main issue however is the order of the routes. The routing
    engines searches the definitions in the order they are declared and stops as soon as it finds a matching one, and in your case the
    IDRoute will match so the routes need to be swapped.
  3. That alone however may cause issues with other route definitions, so its best to make your route uniquely identifiable, for example by specifying the controller name in the route definition.

Your definitions should be

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "ProcessRoute",
        url: "InspectionTemplate/{action}/{id}/{processId}",
        defaults: new { controller = "InspectionTemplate", action = "TemplateBuilder", processId = UrlParameter.Optional }
    );

    routes.MapRoute(
        name: "DateRoute",
        url: "Inspection/{action}/{year}/{month}/{day}",
        defaults: new { controller = "Inspection", action = "Assign", } // assumes all parameters are required
    );

    // The default will only be match if the url does not start with '/InspectionTemplate/' or '/Inspection/'
    routes.MapRoute(
        name: "IDRoute",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional }
    );
}
Comments