Asp.Net Web API Odata Controller Action:
public async Task<IHttpActionResult> Post(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Add(product);
await db.SaveChangesAsync();
return Created(product);
}
Odata client code: (Odata v4 client code generator v4)
static void AddProduct(Default.Container container, ProductService.Models.Product product)
{
container.AddToProducts(product);
var serviceResponse = container.SaveChanges();
foreach (var operationResponse in serviceResponse)
{
Console.WriteLine("Response: {0}", operationResponse.StatusCode);
}
}
I would like to handle exception in a proper way inside AddProducts()
Method while saving the changes.
How can I catch process the ModelState
error which is sent from server return BadRequest(ModelState);
?
Finally I just want to show the error message to the end uses which was sent from server. Example: "Product category is required."
What is the use of ODataException
class? Will this help me?
Please help me.
if I understood well, you want to intercept that the ModelState is not valid, and customize the OData error that is shown to the user.
If you just want that the errors of the invalid model show up in the returned payload, you can use:
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
If you want to fully control the exceptions handling and messages shown, I'd suggest several action points for you to accomplish this:
Intercept ModelState
is not valid: you can do this with a custom ActionFilterAttribute
. In there, you can override the method OnActionExecuting(HttpActionContext actionContext)
. You can access the ModelState
through actionContext.ModelState
, check if it is valid, check the fields that have errors, check the nature of these errors and the generated messages for these errors, etc. The ModelState may be not valid for different reasons, like different types than the expected, not meet requirements specified by DataAnnotations, etc. You can check more on Model validation in here. For your case, I guess the Product entity will have a Required data annotation in the Category field.
After checking all errors, you can throw a custom Exception with the error/list of errors with the messages you want. This is necessary to later intercept your custom exception and be able to return your custom message in the error payload.
Intercept your custom exception: create a custom ExceptionFilterAttribute
to intercept your thrown exceptions. Overriding the
OnException(HttpActionExecutedContext filterContext)
you will have access to the exception, and inspecting it you will be able to build your proper OdataError:
In here you should return the HttpResponseMessage
with the BadRequest http status code and the created ODataError as a payload. As an example of very simple code (you can see that it would depend on how you build your custom exception):
public override void OnException(HttpActionExecutedContext filterContext)
{
Exception ex = filterContext.Exception;
HttpRequestMessage currentRequest = filterContext.Request;
if (filterContext.Exception.GetType() == typeof(YourCustomValidationException))
{
var oDataError = new ODataError()
{
ErrorCode = "invalidModel",
Message = "Your model is not valid.",
InnerError = new ODataInnerError()
{
TypeName = ex.TheEntityThatHasErrors
},
};
foreach (var validationError in ex.ValidationErrors)
{
oDataError.InnerError.Message += validationError + ", ";
}
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
response.RequestMessage = currentRequest;
response.Content = new StringContent(JsonConvert.SerializeObject(oDataError));
filterContext.Response = response;
}
}
Finally, you will have to setup the custom ActionFilterAttribute
and the custom ErrorFilterAttribute
to be used each time that a request reach your controller. You can decorate your actions, controllers, or you can set the filters for all your API controllers in the WebApiConfig
, with config.Filters.Add(...);
You can find more information about all of this in here. In the end, the error and exception handling is the same for ASP.Net Web API, with or without OData; difference is that if you have an OData API, you should return errors in OData style.
Hope all this info is understandable and helps you somehow.