2

Here's what I have tried so far:

 public async Task<IHttpActionResult> Post([FromBody]Word word)
    {
        try
        {
            db.Words.Add(word);

            await db.SaveChangesAsync(User, DateTime.UtcNow);
            return Ok(word);
        }
        catch (Exception ex)
        {
            return BadRequest(new JavaScriptSerializer().Serialize(ex));
        }
    }

When i try to serialize, i get the following error:

{"message":"An error has occurred.","exceptionMessage":"A circular reference was detected while serializing an object of type 'Entities.Models.Core.Word'.","exceptionType":"System.InvalidOperationException","stackTrace":" at .....

I want to return ex.Message and the InnerException. However I don't know if there will be one or more inner exceptions.

Irshu
  • 8,248
  • 8
  • 53
  • 65
Samantha J T Star
  • 30,952
  • 84
  • 245
  • 427
  • Is error occurred at "return Ok(word);" line? – sangram parmar May 03 '16 at 07:17
  • For this particular case I was inserting a duplicate primary key and the inner exception told me this. my problem is 'how to report this and send back to the front-end' – Samantha J T Star May 03 '16 at 07:19
  • i assume you have a error function in you ajax call? you get the response there and do response.exceptionMessage to get the error. – Dr. Stitch May 03 '16 at 07:20
  • http://stackoverflow.com/q/486460/1660178 this one can solve.. – sangram parmar May 03 '16 at 07:29
  • Possible duplicate of [How To Fix Circular Reference Error When Dealing With Json](http://stackoverflow.com/questions/12584986/how-to-fix-circular-reference-error-when-dealing-with-json) – Irshu May 03 '16 at 09:56

2 Answers2

2

I usually use a helper function that deals with exception handling in my Web API projects. I pass the exception that's thrown as an argument to it, then return a HttpResponseException and throw that.

The thrown exception will automatically be serialized to the return type of your Http verb function. In my example I return a Task as it'll serialize any .Net type to a generic object.

If you look at my example below you'll see I have a Method called Get that has its return type set to Task. The object type will be serialized to JSON if the front-end app performs a HTTP GET (in your case a POST) with the Accept header set to 'application/json', when the method returns it'll serialize the return type of Task to json. This also works for the Accept type of text/xml.

I'd recommend filtering specific data in your helper method. you probably don't want people consuming your API to get full stack traces and the like after all, but obviously this is down to your requirements.

public async Task<Object> Get()
{
    object result = null;
    try
    {
        result = await methodThatThrowsException();
    }
    catch (Exception ex)
    {
        throw CreateHttpResponseException(ex);
    }
        return result;
}

Helper Method

private HttpResponseException CreateHttpResponseException(Exception ex)
{
    HttpResponseMessage message;
    if (ex.GetType() == typeof(FaultException<LoginFault>))
    {
        message = new HttpResponseMessage(HttpStatusCode.Forbidden);
    }
    else
    {
        message = new HttpResponseMessage(HttpStatusCode.InternalServerError);
    }

    message.Content = new StringContent(ex.Message);
    return new HttpResponseException(message);
}

In the helper Method, use a StringBuilder to build up what you want to display in your front end. Concatenate and format your error message as you require and then assign the string value to your MessageResponseMessage.Content field.

You'll need to iterate over the Exception InnerException and check to see if it's null, concatenating the exception message etc... as you need.

You could iterate over inner Exceptions using something like

StringBuilder exceptionMessage = new StringBuilder();
Exception inner = ex.InnerException;
while (inner != null)
{
    exceptionMessage.Append(inner.Message)
                    .Append(Environment.NewLine);
    inner = inner.InnerException;
}
Daniel Lane
  • 2,575
  • 2
  • 18
  • 33
1

From you expcetion issue is following you try to save object of Entities.Models.Core.Word which probably have refference to something else and you are using lazy loading. So when serializer try to serialyze your object it fails. there is few ways to fix that.

In global.asax in application_start add

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

Second option would be not to serialize everything but ony what you need

return BadRequest(new JavaScriptSerializer().Serialize(new
            {
                ex.Message,
                ex.StackTrace
            }));
Vova Bilyachat
  • 18,765
  • 4
  • 55
  • 80