使用委托包装异常处理时 Web-API 调用不起作用

Web-API call not working when using delegate to wrap exception handling

我有一个带有自托管 OWIN 的 .NET 4.5.2 应用程序来支持内部 Web api。为了进行一般的异常处理,我尝试将所有调用包装在方法 "TryOk" 中,并以委托作为参数。 TryOk 然后会关心异常并处理它们。

我尝试在没有委托的情况下调用 web-api,它成功了。仅在使用委托时出现错误。

我最大限度地减少了代码并删除了所有代码镇流器,如异步。

[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); }
}

我得到异常 "Error getting value from 'Length' on 'Microsoft.Owin.Host.HttpListener.RequestProcessing.HttpListenerStreamWrapper'.",内部异常 "This stream does not support seek operations"。

异常详情:

"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)"
}

我做错了什么?

感谢您的任何回答或想法。

-- 贾兹

您是 ,这就是导致您出现该错误的原因。

在这一行中,您在回调函数中 return 编辑了一个 IHttpActionResult:

 return TryOk(() => { return Ok("you say " + echo ?? "nothing"); });

您不需要调用Ok(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); }
}

编辑 1:

您甚至可以通过检查 callbac 函数的 return 值使您的 TryOk 方法更加智能。

try
{
    var returnValue = call();

    if(returnValue is IHttpActionResult)
        return returnValue;

    return Ok(returnValue);
}
catch(Exception ex)
{
    return BadRequest(ex.Message);
}

我还有一个建议,我推荐你使用A global Exception Filter