Reputation: 27599
I have a situation that I am working on a blogging website which has urls of the form:
/blog/{id}/{title-slug}
The {title-slug} is purely a user friendly string designed to make the url look nicer. The id alone is enough to uniquely determine everything.
I have some code in a global ActionFilterAttribute which will recognise that the {title-slug} is missing (or incorrect) and it then does
filterContext.Result = new RedirectResult(url.Action(action, controller, routeValueDictionary));
This works mostly fine except for one problem. I have multiple routes that match the controller and action and it seems to just choose the first one...
Lets see some code. My relevant routes look like this:
routes.MapRoute
(
"ShowFeedAndFollow",
"blog/{shortcode}/{slug}/followme",
new { controller = "Public", action = "ShowFeed", shortcode = "", slug = "", followme = true } // Parameter defaults
);
routes.MapRoute
(
"ShowFeed",
"blog/{shortcode}/{slug}",
new { controller = "Public", action = "ShowFeed", shortcode = "", slug = "" } // Parameter defaults
);
My code to redirect if the slug is wrong looks (in simplified form) like this:
var slug = filterContext.RouteData.Values["slug"] == null ? "" : filterContext.RouteData.Values["slug"].ToString();
var action = filterContext.RouteData.Values["action"] == null ? "" : filterContext.RouteData.Values["action"].ToString();
var controller = filterContext.RouteData.Values["controller"] == null ? "" : filterContext.RouteData.Values["controller"].ToString();
RouteValueDictionary routeValueDictionary = new RouteValueDictionary(filterContext.RouteData.DataTokens);
var canonicalSlug = GetCanonnicalSlug();
routeValueDictionary["slug"] = canonicalSlug;
if (!String.IsNullOrEmpty(canonicalSlug) && !slug.Equals(canonicalSlug))
{
var url = new UrlHelper(filterContext.RequestContext);
filterContext.Result = new RedirectResult(url.Action(action, controller, routeValueDictionary));
}
As you can see I can get the action and controller from the current route data and make a new routeValueDictionary with the modified route data. The problem I have is that it picks up the url for the first route (called "ShowFeedAndFollow") and not the one I actually want and that it came in as, "ShowFeed".
I cannot hardcode the route name (because the same code currently works for blogs and posts in the blogs). I have the route object (filterContext.RouteData.Route
) but I can't seem to find a way to generate a url given that object.
I can probably just reorder the routes so that the one I want is first. However this is clearly a fragile solution that breaks if I ever decide to do something that changes the order of these things.
So my question in summary then is this:given I am in a filter attribute and have all the data about the route that got me here and I want to just redirect to the exact same route/url but with one parameter changed, how can I best do this?
Upvotes: 2
Views: 1268
Reputation: 53
To do the routing with parameters in filterContext it will be better to use RedirectToRouteResult instead of RedirectResult
You can simply do this:
First collect all route data include Controller Name, Action Name and other parameters.
var routeData = filterContext.RouteData.Values;
Then make any change that needed in parameters like this:
routeData["slug"] = routeData["slug"].ToString().Replace("-", "_");
and finally use RedirectToRouteResult instead of RedirectResult:
filterContext.Result = new RedirectToRouteResult(routeData);
Upvotes: 0