0

Is there any way I can implement a convenience method that uses a Controller's protected method(s) without using a base controller, which is recommended against here? For example, I want to return an ActionResult based on whether a returnUrl query string param has been passed. What I really want is an extension method like this:

public static class ControllerExtensions {
    public static ActionResult RedirectReturnUrlOrDefaultAction(this Controller thisController, string returnUrl, string defaultAction) {
        if (!string.IsNullOrEmpty(returnUrl) && thisController.Url.IsLocalUrl(returnUrl)) {
            return thisController.Redirect(returnUrl);
        }
        else {
            return thisController.RedirectToAction(defaultAction);
        }
    }
}

So that I could then say this:

return this.RedirectReturnUrlOrDefaultAction(Request.QueryString["returnUrl"], "Index");

... from within a Controller. But of course that extension method doesn't compile because for some reason, methods like Redirect are protected internal (why are they protected internal, by the way?)

Is there a decent way I can do this without using a base controller? If not, might this be one good reason to actually use a base controller, or is there something flawed with my design?

Community
  • 1
  • 1
Jez
  • 27,951
  • 32
  • 136
  • 233
  • While I don't believe it's possible to access any non-public method/properties from extension methods, would it be possible for you to to return `new RedirectResult` instead of `controller.Redirect`? – Matthew Dec 07 '12 at 15:41
  • Hmm, it may well be. But what about the `RedirectToAction`? – Jez Dec 07 '12 at 15:42
  • You might be able to use `UrlHelper.Action` to determine the URL. http://msdn.microsoft.com/en-us/library/dd504960.aspx – Matthew Dec 07 '12 at 15:47

1 Answers1

1

What about:

public static class ControllerExtensions {
    public static ActionResult RedirectReturnUrlOrDefaultAction(this Controller controller, Func<string, ActionResult> returnUrlRedirectAction, Func<ActionResult> defaultAction) {
        string returnUrl = controller.Request.QueryString["returnUrl"];
        if (!string.IsNullOrEmpty(returnUrl) && controller.Url.IsLocalUrl(returnUrl)) {
            return returnUrlRedirectAction(returnUrl);
        }
        else {
            return defaultAction();
        }
    }
}

This can then be used in the controller as:

return this.RedirectReturnUrlOrDefaultAction(ret => Redirect(ret), () => RedirectToAction("Index"));
Jez
  • 27,951
  • 32
  • 136
  • 233
Felice Pollano
  • 32,832
  • 9
  • 75
  • 115
  • Yep, calling back the controller. Not bad, although wouldn't be necessary if `RedirectToAction` etc. didn't have stupid privacy restrictions. – Jez Dec 07 '12 at 16:06
  • OK, I came up with this solution based on yours: http://pastebin.com/fcMuXbGb - if you replace your solution with this one, I'll mark yours as the correct answer. – Jez Dec 07 '12 at 16:29