4

I've got this code.

 public ActionResult Index()
 {
        ReceiptModel model = new ReceiptModel();

        try
        {
            model = new ReceiptModel(context);
        }
        catch (BussinessException bex)
        {
            ModelState.AddModelError("Index", bex.MessageToDisplay);
            return View("Index");
        }
        return View(model);
 }

BussinesException ir returned from database and then displayed for user. I have to put on every controller method try-catch statement, which is a bit tedious. Is there any easier way how to handle these exceptions?

P.S. All other exceptions are handled with HandleExceptionAttribute

UPDATE:

I used Floradu88 approach. So Now i have something like this.

public sealed class HandleBussinessExceptionAttribute : HandleErrorAttribute, IExceptionFilter
    {

        public override void OnException(ExceptionContext filterContext)
        {
            filterContext.Controller.TempData["UnhandledException"] = filterContext.Exception;
            filterContext.ExceptionHandled = true;

            ((Controller)filterContext.Controller).ModelState.AddModelError(
                 ((BussinessException)filterContext.Exception).Code.ToString(),
                 ((BussinessException)filterContext.Exception).MessageToDisplay
             );

            filterContext.Result = new ViewResult
            {
                ViewName = this.View,
                TempData = filterContext.Controller.TempData,
                ViewData = filterContext.Controller.ViewData,
            };


        }
    }

and on Controller action i put

[HandleBussinessExceptionAttribute(Order = 2, ExceptionType = typeof(BussinessException), View = "Login")]

i also tried in exception handler:

 filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(filterContext.RouteData));

and then handle error in action with ModelState.IsValid but values to action comes null. So for now i use first approach. When i have a bit more time i'll try to fix second approach.

lew
  • 77
  • 4
  • 11
  • 1
    Are you using mvc 4? Is so, you may use filtering – radu florescu Mar 26 '13 at 07:52
  • Yes. I'm using MVC 4. How it should go with filtering? catchException in HandleExceptionAttribute => add Error to ModelState => return to same page? – lew Mar 26 '13 at 08:16
  • 1
    You can using a global action filter. It works quite well, and keeps your code integrated within your application. [How do it](http://www.codeproject.com/Articles/422572/Exception-Handling-in-ASP-NET-MVC) And you can look for HttpModule. An HTTP module works as well, of course, but this will mean seperating the code from your main application and maintaining it seperately. If you code used in multiple applications, then I would use a global filter. – user571874 Mar 26 '13 at 08:49

2 Answers2

2

Please read the documentation on this part: http://msdn.microsoft.com/en-us/library/gg416513%28v=vs.98%29.aspx
http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling
http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/understanding-action-filters-cs

Too much content to be posted here:

 public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute 
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            if (context.Exception is NotImplementedException)
            {
                context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
            }
        }
    }

And your controller:

public class ProductsController : ApiController
{
    [NotImplExceptionFilter]
    public Contact GetContact(int id)
    {
        throw new NotImplementedException("This method is not implemented");
    }
}
radu florescu
  • 4,315
  • 10
  • 60
  • 92
0
  1. According to this post, Create a custom binder and put the model in TempData:

    public class AppBinder : DefaultModelBinder
    {
        protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            base.OnModelUpdated(controllerContext, bindingContext);
            controllerContext.Controller.TempData["model"] =    bindingContext.Model;
        }
    }
    
  2. Register it in global.asax:

    ModelBinders.Binders.DefaultBinder = new AppBinder();
    
  3. Create a BaseController and override the OnException:

    protected override void OnException(ExceptionContext filterContext)
    {
        filterContext.ExceptionHandled = true;
    
        this.ModelState.AddModelError(string.Empty, filterContext.Exception.Message);
    
        filterContext.Result = new ViewResult
        {
            ViewName = filterContext.RouteData.Values["action"].ToString(),
            TempData = filterContext.Controller.TempData,
            ViewData = filterContext.Controller.ViewData
        };
    
        base.OnException(filterContext);
    }
    

All Actions int The Controllers which inherited from this base controller will show their unhandled exceptions their own view in validation summery (remember to have

@Html.ValidationSummary(true) 

in page). it works for me, hope works for you too!

Community
  • 1
  • 1
Hadelo
  • 53
  • 7