Chris
Chris

Reputation: 27599

Redirect to same route with different parameter values

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

Answers (1)

Amin Karampour
Amin Karampour

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

Related Questions