Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error Handling for ASP.NET Odata Web API

I'm interested in knowing what are the best practices being followed to raise exceptions in the ODataController.

If you raise an exception in the method it is translated to response code of 500 by default and the content has details on the error. I would like to be explicit of the response code and send 400 in cases of invalid key.

For example: If the input request has an invalid key would like to return a HttpResponseCode of 400 and content should have the error details similar to raising an exception.

Thanks a lot for your inputs

like image 694
user2883779 Avatar asked Oct 15 '13 19:10

user2883779


3 Answers

OData (at least since v3) uses specific json to represent errors:

{
    "error": {
        "code": "A custom error code",
        "message": {
            "lang": "en-us",
            "value": "A custom long message for the user." 
        },
        "innererror": {
            "trace": [...],
            "context": {...}
        }
    }
}

Microsoft .Net contains Microsoft.Data.OData.ODataError and Microsoft.Data.OData.ODataInnerError classes to form OData error on a server side.

To form proper OData error response (HttpResponseMessage), that contains error details you can:

1) form and return HttpResponseMessage in controller's action using System.Web.OData.Extensions.HttpRequestMessageExtensions.CreateErrorResponse method

return Request.CreateErrorResponse(HttpStatusCode.Conflict, new ODataError { ErrorCode="...", Message="...", MessageLanguage="..." }));

2) throw HttpResponseException using the same method for creating HttpResponseMessage

throw new HttpResponseException(
    Request.CreateErrorResponse(HttpStatusCode.NotFound,  new ODataError { ErrorCode="...", Message="...", MessageLanguage="..." }));

3) throw custom typed exception and convert it using Web Api action filters

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext context)
    {
        if (context.Exception is CustomException)
        {
            var e = (CustomException)context.Exception;

            var response = context.Request.CreateErrorResponse(e.StatusCode, new ODataError
            {
                ErrorCode = e.StatusCodeString,
                Message = e.Message,
                MessageLanguage = e.MessageLanguage
            });
            context.Response = response;
        }
        else
            base.OnException(context);
    }
}
like image 90
Ivan Samygin Avatar answered Sep 30 '22 09:09

Ivan Samygin


Use HttpResponseException,
e.g. throw new HttpResponseException(HttpStatusCode.NotFound);.
Details can be found here.

like image 44
Vladimir Avatar answered Oct 02 '22 09:10

Vladimir


For ASP.NET Core with OData, replace the EnableQueryAttribute on your Get method with a custom attribute that catches ODataException and throws a custom exception. In most cases, this allows standard error handling to step in as expected. Originally found this solution at https://github.com/OData/WebApi/issues/1898.

For your custom attribute, use something like the following:

public class CustomEnableQueryAttribute : EnableQueryAttribute
{
    public override void ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)
    {
        try
        {
            base.ValidateQuery(request, queryOptions);
        }
        catch (ODataException e)
        {
            throw new CustomException(e.Message, e){UserMessage = "Invalid OData query."};
        }
    }
}

On your Get method, use something like the following:

[HttpGet, CustomEnableQuery]
public virtual IQueryable<TDomainDto> Get()
{
    return Repository.Get();    
}
like image 28
flipdoubt Avatar answered Oct 04 '22 09:10

flipdoubt