I have a .NET 4.5.2 application with a self hosted OWIN to support a internal web api. To have a general exception handling, I tried to wrap all calls inside a method "TryOk" with a delegate as parameter. TryOk will then care about exceptions and handle them.
I tried to call the web-api without delegate and it worked. only when using delegate I get an error.
I reduced the code to the max and removed all code balast like async.
[HttpPost, Route("echo")]
public IHttpActionResult MyEchoApi([FromBody]string echo)
{
// this is working: direct return
//return Ok("you say " + echo ?? "nothing");
// this is also working: direct return with exception handling
//try { return Ok(call()); }
//catch (Exception ex) { return BadRequest(ex.Message); }
// this is not working: wrapping in delegate
return TryOk(() => { return Ok("you say " + echo ?? "nothing"); });
}
private IHttpActionResult TryOk<T>(Func<T> call)
{
try { return Ok(call()); }
catch (Exception ex) { return BadRequest(ex.Message); }
}
I get the exception "Error getting value from 'Length' on 'Microsoft.Owin.Host.HttpListener.RequestProcessing.HttpListenerStreamWrapper'." with inner exception "This stream does not support seek operations".
Exception details:
"ExceptionMessage": "Error getting value from 'Length' on 'Microsoft.Owin.Host.HttpListener.RequestProcessing.HttpListenerStreamWrapper'.",
"ExceptionType": "Newtonsoft.Json.JsonSerializationException",
"StackTrace": " bei Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
bei Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
bei Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
bei System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)
bei System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)
bei System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
--- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde ---
bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
bei System.Web.Http.Owin.HttpMessageHandlerAdapter.<BufferResponseContentAsync>d__27.MoveNext()",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "This stream does not support seek operations.",
"ExceptionType": "System.NotSupportedException",
"StackTrace": " bei System.Net.HttpResponseStream.get_Length()
bei GetLength(Object )
bei Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)"
}
What am I doing wrong?
Thank you for any answer or idea.
-- jaz
You are creating a response over a response and that's why it cause your that error.
On this line, you have returned an IHttpActionResult in your callback func:
return TryOk(() => { return Ok("you say " + echo ?? "nothing"); });
you don't need to call Ok(call())
, just call return call()
.
private IHttpActionResult TryOk<T>(Func<T> call)
{
// call itself returns an Ok http action result, you are returning a reposnse on another response! just change to call();
try { return Ok(call()); }
catch (Exception ex) { return BadRequest(ex.Message); }
}
Edit 1:
you can even make your TryOk
method much more smarter by checking the return value of your callbac func.
try
{
var returnValue = call();
if(returnValue is IHttpActionResult)
return returnValue;
return Ok(returnValue);
}
catch(Exception ex)
{
return BadRequest(ex.Message);
}
Another suggestion I have, I recommend you to use A global Exception Filter.