Rahul
Rahul

Reputation: 77876

Is it possible to redirect to view from a non-controller class in MVC

Was working on logging using NLOG and there is separate class @ global level from where logging happens. Per requirement, have to redirect to "Error" view (Error.cshtml) from that class after logging is over.

But it's a non-controller class and hence can't use usual methods like RedirectToAction() or simply return View("Error").

Is there any way possible of doing that? I tried Response.Redirect() but doesn't do anything.

HttpContext.Current.Response.Redirect("/Help/Error",true);

Error.cshtml is a plain HTML file with text like There is some error ... please contact admin which is present under Views/Shared/* folder.

Logging class is present in a separate folder say logging under root folder.

On every call to Action method if any exception occurs then the logger gets invoked automatically which does it's stuff of logging and finally should redirect to the error view.

Upvotes: 1

Views: 2196

Answers (2)

Shyju
Shyju

Reputation: 218732

You can create your own base controller and handle the exceptions in the onexception event

public class BaseController : Controller
{
    protected override void OnException(ExceptionContext filterContext)
    {
       //Do your logging
       // and redirect / return error view
        filterContext.ExceptionHandled = true;
        // If the exception occured in an ajax call. Send a json response back
        // (you need to parse this and display to user as needed at client side)
        if (filterContext.HttpContext.Request.Headers["X-Requested-With"]=="XMLHttpRequest")
        {
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new { Error = true, Message = filterContext.Exception.Message }
            };
            filterContext.HttpContext.Response.StatusCode = 500; // Set as needed
        }
        else
        {
            filterContext.Result = new ViewResult { ViewName = "Error.cshtml" }; 
            //Assuming the view exists in the "~/Views/Shared" folder
        }
    }
}

Now for your other controllers, inherit from this bascontroller.

public class ProductsController : BaseController 
{
   public ActionResult Die()
   {
     throw new Exception("I lost!");
   }
}

If you want to do a redirect (a new GET call) to your Error action method, you can replace the ViewResult with a RedirectToRouteResult.

filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary {
                                               {"controller", "Home"}, {"action", "Error"}
                                              };

Upvotes: 2

AaronLS
AaronLS

Reputation: 38367

You don't say how the logging code is called automatically "the logger gets invoked automatically". So I'm going to recommend a HandleErrorAttribute. This requires you have a Error.cshtml in your shared views folder, but you could specify a different view in filterContext.Result

public class CustomErrorAttribute : HandleErrorAttribute 
{

    public override void OnException(ExceptionContext filterContext)
    {
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;// This causes the webconfig httpErrors section to be ignored, since we are handling the exception
        filterContext.ExceptionHandled = true;

        //... log error

        filterContext.HttpContext.Response.ClearContent();// Removes partially rendered content

        // just information to be passed in the view model, this does NOT define which view is displayed next.  It tells us where the error came from.
        var controllerName = (string)filterContext.RouteData.Values["controller"];
        var actionName = (string)filterContext.RouteData.Values["action"];
        var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
        // This presents an error page view.  By default if a View is not passed to the Attribute, then this is Error.cshtml in Shared.
        filterContext.Result = new ViewResult
        {
            ViewName = View,  // View & Master are parameters from the attribute e.g. [ErrorAttribute(View="OtherErrorView")], by default the view is the "Error.cshtml" view
            MasterName = Master,
            ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
            TempData = filterContext.Controller.TempData
        };

        filterContext.Exception = null;


    }
}

Upvotes: 1

Related Questions