Search code examples
c#error-handlingasp.net-web-api2odata

WebApi2 OData return custom error object


I've searched this intensive but can't get it to work.

I've haven an Web AP2 OData API and need to return a custom error class.

Here is what I have:

public class Error
{
    public string Code { get; set; }
    public string Message { get; set; }
}

In Global.asax.cs

protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);            

        GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageInterceptor());
    }


 public class MessageInterceptor : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {

        return base.SendAsync(request, cancellationToken).ContinueWith(
                    task =>
                    {
                        var body = task.Result.Content.ReadAsStringAsync().Result;
                        var resultObj = JsonConvert.DeserializeObject(body.Replace("value", "Results"));                            
                        task.Result.Content = new ObjectContent(typeof(object), resultObj, new JsonMediaTypeFormatter());
                        return task.Result;
                    }, cancellationToken);
    }
}

In WebApiConfig,cs

 public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {

 config.Filters.Add(new  HandleApiExceptionAttribute());

}

}

public class HandleApiExceptionAttribute : ExceptionFilterAttribute, IExceptionFilter
{
    public override void OnException(HttpActionExecutedContext context)
    {
        if (context.Exception is Error)
        {
            var res = context.Exception.Message;

            //Define the Response Message
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = new StringContent(res),
                ReasonPhrase = res
            };

            //Create the Error Response
            context.Response = response;
        }
    }


 public class OrdersController : ODataControllerA controller
{
    private Context db = new Context();

    // GET: odata/Orders
    [Queryable]
    public IQueryable<Orders> GetOrders(ODataQueryOptions<Orders> opts)

{

<some code producing error>

Error theError = new Error()
        {
            Code = "1000",
            Message = "Geen filter gespecificeerd"
        };

        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest, theError);
        //return Request.CreateResponse(HttpStatusCode.BadRequest, theError);
        throw new HttpResponseException(response);

}

When I try this this crashes in the MessageInterceptor.

This is there because a third party consuming the API want's it in the specific format.

When the code runs correct it returns results{}

On error it should return Error{code:, message: }

Anyone ideas?

Jeroen


Solution

  • This is what I came up with:

    I changed the controller to:

     [Queryable, BasicAuthentication]
        public IHttpActionResult GetOrders(ODataQueryOptions<Orders> opts)
        {
            else
            {     
    
                Error theError = new Error()
                {
                    Code = "1000",
                    Message = "Geen filter gespecificeerd"
                };
    
                return new ErrorResult(theError, Request);
    
            }
    
            return Ok(resultList);
        }
    

    Using this class:

    public class ErrorResult : IHttpActionResult
    {
        Error _error;
        HttpRequestMessage _request;
    
        public ErrorResult(Error error, HttpRequestMessage request)
        {
            _error = error;
            _request = request;
        }
    
        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {            
    
            List<Error> _errorList = new List<Error>();
            _errorList.Add(_error);
    
            error err = new error()
            {
                errors = _errorList
            };
    
            var response = new HttpResponseMessage(HttpStatusCode.BadRequest)
            {
                Content = new ObjectContent<error>(err, new JsonMediaTypeFormatter()),
                RequestMessage = _request
            };
            return Task.FromResult(response);
        }
    }
    
    public class Error 
    {
        public string Code { get; set; }
        public string Message { get; set; }
    }
    
    public class error
    {
        public List<Error> errors { get; set; }
    }