1

I have this class:

public abstract class MyController : Controller
{
  protected override void OnActionExecuting(ActionExecutingContext filterContext)
  {
      string viewPath = filterContext/*... .ViewPath*/;
      viewPath = "Some new View Path";
  }
}

And I'd like to retrieve and replace the executing view's path by another one. I have tried to debug-view the filter context on a web call, however I did not manage to find a view which is about to render.

How do I do that?

AgentFire
  • 8,944
  • 8
  • 43
  • 90

1 Answers1

5

From MSDN:

Controller.OnActionExecuting Method: Called before the action method is invoked. At this stage, no ActionResult exists since the Action didn't execute yet.

You better use the OnResultExecuting instead:

protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
    var viewResult = filterContext.Result as ViewResult;

    if (viewResult != null)
    {
        var razorEngine = viewResult.ViewEngineCollection.OfType<RazorViewEngine>().Single();
        var viewName = !String.IsNullOrEmpty(viewResult.ViewName) ? viewResult.ViewName : filterContext.RouteData.Values["action"].ToString();
        var razorView = razorEngine.FindView(filterContext.Controller.ControllerContext, viewName, viewResult.MasterName, false).View as RazorView;
        var currentPath = razorView.ViewPath;
        var newPath = currentPath.Replace("..", "...");
        viewResult.View = new RazorView(filterContext.Controller.ControllerContext, newPath, razorView.LayoutPath, razorView.RunViewStartPages, razorView.ViewStartFileExtensions);
    }

    base.OnResultExecuting(filterContext);
}
haim770
  • 48,394
  • 7
  • 105
  • 133
  • The view name is `"Index"` or `""` and never the full view path. How do I get a string like `"~/Views/Controller/ViewName"`? – AgentFire Jun 13 '13 at 09:32
  • I revised my answer accordingly. – haim770 Jun 13 '13 at 09:39
  • The `viewResult.View` property is always null, even if the viewname is originally correct. – AgentFire Jun 13 '13 at 09:42
  • i am sorry for the question, it is not correct itself. There is no way for MVC to know the exact view path before `OnResultExecuting` method is completed. – AgentFire Jun 13 '13 at 09:46
  • Accepted at least for I found a solution based on your answer. – AgentFire Jun 13 '13 at 09:46
  • I revised my answer again. the approach is a bit risky since it's assuming you're not overriding the default `ViewEngine` and using it to resolve the `ViewPath`. i guess you can apply some more precautions to the code and have it working just fine. – haim770 Jun 13 '13 at 09:55
  • One more revision. does work for me now, even when no view name specified (`return View()`). – haim770 Jun 13 '13 at 10:37
  • After replacing the old viewpath with the new path, the url in the address bar remains same. Why ? – Pankaj Jun 13 '13 at 11:30
  • @abcdefghi, are you serious? – haim770 Jun 13 '13 at 11:31
  • Why would it change the address bar in the client browser? – haim770 Jun 13 '13 at 11:34
  • I am assuming that the View Path is changed so it should change the route data as well. – Pankaj Jun 13 '13 at 11:36
  • I don't think so. `OnResultExecuting` is taking place way after routing process and my code doesn't change `RouteData`. – haim770 Jun 13 '13 at 11:43
  • @haim770 : Can you please explain why it should not change the url? – Pankaj Jun 13 '13 at 11:43
  • @abcdefghi because it is the **redirect response** required in order to notify browser about some changes. – AgentFire Jun 13 '13 at 11:48
  • @AgentFire - As you said, it needs Redirect response to nofify browser about changes. Can you please tell what is happening in this context which is updating the View and not updating the url? – Pankaj Jun 13 '13 at 11:51
  • 1
    In Asp.net MVC, a request url is being mapped (using registered routes) to `controller`.`action`, the action is then responsible for generating the output (which is `ViewResult` in our case). it doesn't matter what the action decides to return (or what `View` file it loads), it shouldn't affect the url (unless it's explicit `RedirectResult` which will usually cause another http request). – haim770 Jun 13 '13 at 12:01