ASP.NET Core Pitfalls – Redirect to Action Keeps Route Parameters

When you redirect after a POST – following the famous Post-Redirect-Get pattern – but your previous view was constructed using a route parameter, then it will be sent to the redirect action as well.

For example, say you are responding to a request for /Filter/Smartphone, where Smartphone is a route parameter, you POST it to some controller action and at the end you redirect to the Index action using the RedirectToAction method:

return this.RedirectToAction(nameof(Index));

The browser will issue the GET request for Index but keeps the Smartphone route parameter, which is not good.

The solution is to pass a routeValues parameter to RedirectToAction that doesn’t contain any of the possible route parameters. One way to do it would be to create a dictionay with all action parameters nullified:

return this.RedirectToAction(nameof(Index), MethodBase.GetCurrentMethod().GetParameters().ToDictionary(x => x.Name, x => (object) null));

The solution to have this done automatically lies in the MethodBase.GetCurrentMethod() method. This way, you are sure to avoid any unwanted route parameters on your next request.

In case you are wondering, passing null, a dictionary without entries or object won't work, the only other way is to pass an anonymous value with the parameters explicitly set to null.

                             

3 Comments

  • Heyy, Really helped me. Thank you very much for sharing it dear.

  • Thanks for a great article!

    I used this as a inspiration and created a basecontroller that exposes this as a method to avoid having the MethodBase.Get...-code everywhere.

    Figured I'll share it here:

    public abstract class MvcController : Controller
    {
    public RedirectToActionResult RedirectToActionCleanParameters(string actionName)
    {
    // Get frames from stack trace
    StackTrace stackTrace = new StackTrace();
    var stackTraceFrames = stackTrace.GetFrames();

    MethodBase callingControllerMethod = null;

    // Need to skip the first method as that is this method
    // RedirectToActionCleanParameters(string actionName).
    foreach (var frame in stackTraceFrames.Skip(1))
    {
    if (frame != null)
    {
    var method = frame.GetMethod();
    if (method != null)
    {
    var declaringType = method.DeclaringType;

    // Check if the declaring type is a Controller
    if (declaringType != null && declaringType.IsSubclassOf(typeof(Controller)))
    {
    callingControllerMethod = method;
    break;
    }
    }
    }
    }

    if (callingControllerMethod != null)
    {
    var res = callingControllerMethod.GetParameters().ToDictionary(x => x.Name, x => (object) null);
    return RedirectToAction(actionName, res);
    }

    throw new InvalidOperationException("Can't find Controller method in stack trace.");

    }
    }

    Make a controller that uses this:

    public class MyController : MvcController {

    public async Task<IActionResult> Confirm()
    {
    return RedirectToActionCleanParameters(nameof(Confirm));
    }
    }

    All the best!

  • Hi, Markus! Cool, glad you liked it! :-)

Add a Comment

As it will appear on the website

Not displayed

Your website