0

I use MVC 4 and have moved some logic into an authorize filter. I am trying redirect to an error page based on not being authorized. I would like to set the last page route and a few other properties to catch the error.

Below is my override

        //  handle unauthorized
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        filterContext.Controller.ViewBag.LastRoute = filterContext.RouteData;
        filterContext.Controller.ViewBag.Issue = "put...val here";

        var routeValues = new RouteValueDictionary(new
        {
            controller = "Error",
            action = "Oops"
        });

        filterContext.Result = new RedirectToRouteResult(routeValues);
    }

controller

        [AllowAnonymous]
    public ActionResult Oops()
    {
        var m = new Core.Models.ErrorModel();

        var v = ViewBag.Issue;  // == null

        return View("~/Views/Error/Oops.cshtml", m);
    }

I tried how to set values to viewbag in actionfilterattribute asp mvc 5 for action filters and it works

Any help would be appreciated.

EDIT:

Sorry when I get to the controller the value for: ViewBag.Issue = null.

I'm not sure how to set the property and have it hold value.

Community
  • 1
  • 1
Killilea
  • 311
  • 7
  • 17
  • It is not clear from your post what is not working or what your question is exactly. – David Tansey Dec 13 '15 at 21:58
  • 2
    You are setting the Result to redirect the user, so the original targeted action never gets invoked. Instead, the browser ends up issuing another request to the Error/Oops endpoint, so you're in a new request with a separate ViewBag by then. Consider using TempData to make the information available to the next request, or consider returning the View() result directly from your action filter (leaving the user on the original action, but showing them a page that looks like the Oops action). – StriplingWarrior Dec 13 '15 at 22:27

1 Answers1

6

RedirectToRouteResult is going to send a redirect response to the browser and browser will issue a brand new GET request to the url specified. ViewBag data do not survive between 2 http requests.

You may use TempData which will keep the data between 2 seperate http requests. You can set your TempData value in one action method and any action method that is called after this can get values from the TempData object and then use it. TempData use Session behind the scene to store data. The value of TempData persists until it is read or until the session times out. This is ideal for scenarios such as redirection because the values in TempData are available beyond a single request.

So in your action filter you can set the TempData dictionary instead of ViewBag.

filterContext.Controller.TempData["Issue"] = "Robots are laughing non stop";

var routeValues = new RouteValueDictionary(new
{
    controller = "Home",
    action = "Oops"
});

filterContext.Result = new RedirectToRouteResult(routeValues);

Now in your Oops action method, you may read the TempData value you set

public ActionResult Oops()
{
  var issueDetails = TempData["Issue"];
  // TO DO : Do something useful with issueDetails :)
  return View();
}

Keep in mind that TempData values won't be available after you read it. So if you want to read it in your view again, set it again or better use a view model and set the already read value as the property value of your view model.

Shyju
  • 214,206
  • 104
  • 411
  • 497