Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a web api I'm working on using the MVC 4 Web API framework. If there is an exception, I'm currently throwing a new HttpResposneException. ie:

if (!Int32.TryParse(id, out userId))
    throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid id")); 

This returns an object to the client that is simply {"message":"Invalid id"}

I would like to gain further control over this response to exceptions by returning a more detailed object. something like

{
 "status":-1,
 "substatus":3,
 "message":"Could not find user"
 }

How would I go about doing this? Is the best way to serialize my error object and set it in the response message?

I've also looked into the ModelStateDictionary a bit and have come up with this bit of a "hack", but it's still not a clean output:

var msd = new ModelStateDictionary();
msd.AddModelError("status", "-1");
msd.AddModelError("substatus", "3");
msd.AddModelError("message", "invalid stuff");
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, msd));

edit
looks like a custom HttpError is what I need. This seems to do the trick, now to make it extensible from my business layer...

var error = new HttpError("invalid stuff") {{"status", -1}, {"substatus", 3}};
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, error));
share|improve this question

3 Answers

up vote 2 down vote accepted

I think this will do the trick:

Create a custom exception class for the business layer:

 public class MyException: Exception
 {
    public ResponseStatus Status { get; private set; }
    public ResponseSubStatus SubStatus { get; private set; }
    public new string Message { get; private set; }

    public MyException()
    {}

    public MyException(ResponseStatus status, ResponseSubStatus subStatus, string message)
    {
        Status = status;
        SubStatus = subStatus;
        Message = message;
    }
 }

Create a static method to generate a HttpError from an instance of MyException. I'm using reflection here so I can add properties to MyException and always have them returned w/o updating Create:

    public static HttpError Create<T>(MyException exception) where T:Exception
    {
        var properties = exception.GetType().GetProperties(BindingFlags.Instance 
                                                         | BindingFlags.Public 
                                                         | BindingFlags.DeclaredOnly);
        var error = new HttpError();
        foreach (var propertyInfo in properties)
        {
            error.Add(propertyInfo.Name, propertyInfo.GetValue(exception, null));
        }
        return error;
    }

I currently have a custom attribute for a general exception handler. All exceptions of type MyException will be handled here:

public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext context)
    {
        var statusCode = HttpStatusCode.InternalServerError;

        if (context.Exception is MyException)
        {
            statusCode = HttpStatusCode.BadRequest;
            throw new HttpResponseException(context.Request.CreateErrorResponse(statusCode, HttpErrorHelper.Create(context.Exception)));
        }

        if (context.Exception is AuthenticationException)
            statusCode = HttpStatusCode.Forbidden;

        throw new HttpResponseException(context.Request.CreateErrorResponse(statusCode, context.Exception.Message));
    }
}

I'll play around with this a bit more and update as I find holes in this plan.

share|improve this answer

Take a look at the following article. It will help you gain control over your web api exceptions and error messages: Web Api, HttpError, and the Behavior of Exceptions

share|improve this answer
1  
Thanks. That's similar to what I'm doing - creating a custom ExceptionFilterAttribute –  earthling Jun 6 at 17:54

An alternative answer to the problem...

Ditch Web API and use a MVC controller to return a JsonResult containing whatever is needed. I currently do this a lot, not because I have anything against Web API or RESTful stuff, but because there's always a lot more to return (in my case) that just a HTTP status code and a message.

Another alternative answer...

Persist / log the failure, then have a second Web API request to retrieve the detail or attempt recovery from the error etc.

Always good to have alternatives even if they are less preferable than your accepted answer :)

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.