Search code examples
fubumvc

How do I create an exception-wrapping fubumvc behaviour?


How can I create a fubumvc behaviour that wraps actions with a particular return type, and if an exception occurs while executing the action, then the behaviour logs the exception and populates some fields on the return object? I have tried the following:

public class JsonExceptionHandlingBehaviour : IActionBehavior
{
    private static readonly Logger logger = LogManager.GetCurrentClassLogger();
    private readonly IActionBehavior _innerBehavior;
    private readonly IFubuRequest _request;

    public JsonExceptionHandlingBehaviour(IActionBehavior innerBehavior, IFubuRequest request)
    {
        _innerBehavior = innerBehavior;
        _request = request;
    }

    public void Invoke()
    {
        try
        {
            _innerBehavior.Invoke();

            var response = _request.Get<AjaxResponse>();
            response.Success = true;
        }
        catch(Exception ex)
        {
            logger.ErrorException("Error processing JSON request", ex);

            var response = _request.Get<AjaxResponse>();
            response.Success = false;
            response.Exception = ex.ToString();
        }
    }

    public void InvokePartial()
    {
        _innerBehavior.InvokePartial();
    }
}

But, although I get the AjaxResponse object from the request, any changes I make don't get sent back to the client. Also, any exceptions thrown by the action don't make it as far as this, the request is terminated before execution gets to the catch block. What am I doing wrong?

For completeness, the behaviour is wired up with the following in my WebRegistry:

Policies
    .EnrichCallsWith<JsonExceptionHandlingBehaviour>(action =>
        typeof(AjaxResponse).IsAssignableFrom(action.Method.ReturnType));

And AjaxResponse looks like:

public class AjaxResponse
{
    public bool Success { get; set; }
    public object Data { get; set; }
    public string Exception { get; set; }
}

Solution

  • This won't work with the current version of FubuMVC, unfortunately. The reason is that the call to _innerBehavior.Invoke() will proceed down the rest of the behavior chain including the call to render the JSON output back to the client.

    With current FubuMVC, you can't wrap a behavior and modify its output before the render output behavior is executed.

    I just talked with Jeremy (Miller) about this and we're going to add this capability to FubuMVC so that you can wrap a specific behavior (in this case, the behavior that calls the action) instead of wrapping the entire behavior chain (which is what's happening to you right now).

    I'll comment back here on this StackOverflow question when we have added this feature.