Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating ViewResults outside of Controllers in ASP.NET MVC

Several of my controller actions have a standard set of failure-handling behavior. In general, I want to:

  • Load an object based on the Route Data (IDs and the like)
    • If the Route Data does not point to a valid object (ex: through URL hacking) then inform the user of the problem and return an HTTP 404 Not Found
  • Validate that the current user has the proper permissions on the object
    • If the user doesn't have permission, inform the user of the problem and return an HTTP 403 Forbidden
  • If the above is successful, then do something with that object that's action-specific (ie: render it in a view).

These steps are so standardized that I want to have reusable code to implement the behavior.

My current plan of attack was to have a helper method to do something like this:

public static ActionResult HandleMyObject(this Controller controller, 
    Func<MyObject,ActionResult> onSuccess) {
  var myObject = MyObject.LoadFrom(controller.RouteData).
  if ( myObject == null ) return NotFound(controller);
  if ( myObject.IsNotAllowed(controller.User)) return NotAllowed(controller);
  return onSuccess(myObject);
}

# NotAllowed() is pretty much the same as this
public static NotFound(Controller controller){
    controller.HttpContext.Response.StatusCode = 404
    # NotFound.aspx is a shared view.
    ViewResult result = controller.View("NotFound");
    return result;
}

The problem here is that Controller.View() is a protected method and so is not accessible from a helper. I've looked at creating a new ViewResult instance explicitly, but there's enough properties to set that I'm wary about doing so without knowing the pitfalls first.

What's the best way to create a ViewResult from outside a particular Controller?

like image 269
Craig Walker Avatar asked Feb 22 '10 19:02

Craig Walker


People also ask

How can we call a view from another controller in MVC?

The shared directory is there specifically to share Views across multiple controllers. Just add your View to the Shared subdirectory and you're good to go. If you do return View("~/Views/Wherever/SomeDir/MyView. aspx") You can return any View you'd like.

How do you pass data between a controller and a view?

The other way of passing the data from Controller to View can be by passing an object of the model class to the View. Erase the code of ViewData and pass the object of model class in return view. Import the binding object of model class at the top of Index View and access the properties by @Model.

How pass data from controller controller in ASP.NET MVC?

TempData is used to transfer data from view to controller, controller to view, or from one action method to another action method of the same or a different controller. TempData stores the data temporarily and automatically removes it after retrieving a value. TempData is a property in the ControllerBase class.


2 Answers

Just read this post as I was having the same issue from an action filter. My solution was creating the view action explicitly. This is based on the protected View() method as per the MVC source so it should populate the required properties. Anyway, seems to work without issues.

public static NotFound(Controller controller){
    controller.HttpContext.Response.StatusCode = 404;

    ViewResult result = new ViewResult {
            ViewName = "NotFound",
            ViewData = controller.ViewData,
            TempData = controller.TempData
        };
    return result;
}

A bit late in the day but this worked for me.

like image 193
detaylor Avatar answered Oct 21 '22 05:10

detaylor


As I was writing this I thought of one way.

Rather than have the above code in a helper, I could put it into a subclass of Controller and then subclass this class for my actual controllers. This would allow me to call the protected View() method.

I don't like this particularly much because it requires inheritance to work, but it's still an option.

like image 23
Craig Walker Avatar answered Oct 21 '22 05:10

Craig Walker