Search code examples
c#exceptionpostsharp

How to apply exception aspect in PostSharp with multiple return statements in method?


I am using PostSharp aspects for exception handling inside of Controller in ASP.NET MVC project. Simplified code is like this:

 [ExceptionAspect(AspectPriority = 1)]
 public ActionResult MarkeSettings()
 {
   try{
       SaveData();
       NotifyUser("success");
       return RedirectToAction("A");
     }
   catch(Exception ex){
      NotifyUser(ex.Message);
      return RedirectToAction("B");
   }
 }

I have class ExceptionAspect that inherits from OnExceptionAspect class. In OnException(MethodExecutionArgs args) method I set args.FlowBehavior = FlowBehavior.Continue;.

So, how can I get rid of this try/catch block and control the program execution flow and take an appropriate action for ReturnRedirectToAction()? I read about Sharing state between advices , but couldn't figure out how to apply it on my problem.


Solution

  • When you apply ExceptionAspect to your controller's method, it wraps the method with the try/catch block and calls OnException(MethodExecutionArgs args) from the introduced catch block.

    This means that you can move your common exception handling code from the catch block to the OnException method inside the aspect. I suppose that you want to redirect user to a specific action when exception happens. RedirectToAction is a protected method of the controller that returns RedirectToRouteResult. So you would need to construct and return a correct RedirectToRouteResult instance in the OnException method. To change the return value of the method set the args.ReturnValue to the desired value, and args.FlowBehavior to FlowBehavior.Return.

    Below is the example of the OnExceptionAspect implementation:

    [Serializable]
    public class RedirectOnExceptionAttribute : OnExceptionAspect
    {
        public string ToAction { get; set; }
    
        public override void OnException(MethodExecutionArgs args)
        {
            // NotifyUser(args.Exception.Message);
    
            args.FlowBehavior = FlowBehavior.Return;
    
            object controller = ((ControllerBase) args.Instance).ControllerContext.RouteData.Values["controller"];
            args.ReturnValue = new RedirectToRouteResult(
                new RouteValueDictionary
                    {
                        {"action", this.ToAction},
                        {"controller", controller}
                    });
        }
    }
    

    Applying to controller method:

    [RedirectOnException(ToAction = "B")]
    public ActionResult MarkeSettings()
    {
        SaveData();
        NotifyUser("success");
        return RedirectToAction("A");
    }