如何从ServiceStack中的Action返回流中获取异常的正常/自定义错误响应?

时间:2016-07-11 13:51:18

标签: c# servicestack

我一直在ServiceStack的documentation中冒险从一个返回 Stream 的Action中抛出异常的问题。

问题在于,虽然我服务中的所有其他操作都会返回漂亮的错误,例如:

{
  "ResponseStatus": {
    "ErrorCode": "ArgumentException",
    "Message": "Unable to load data",
    "StackTrace": "[GetData: 7/11/2016 1:02:11 PM]:\n[REQUEST: {Token:asdf,Id:1}]\nServiceStack.HttpError: Unable to load codes from token ---> System.ArgumentException: Unable to load codes from token.............(abridged)
  }
}

有一个Action的返回类型为Stream,无论返回的异常类型如何,http客户端都会收到以下响应:

使用处理程序(根据SS文档):

Error: ArgumentNullException: As result 'ErrorResponse' is not a supported responseType, a defaultAction must be supplied
Parameter name: defaultAction

没有任何处理程序:

'no content'

400

非常感谢任何帮助。

示例代码 - >

以下是行动的一个例子:

[AddHeader(ContentType = "application/pdf")]
public Stream Get(GetPdfRequest request)
{
    throw new NotImplementedException("FAKE EXCEPTION");
}

并在APPHOST的Configure()方法中:

this.UncaughtExceptionHandlers.Add((req, res, operationName, ex) =>
            {
                var logger = LogManager.GetLogger(GetType());
                logger.Error("Unhandled error in API during request binding.", ex);

                res.Write("Error: {0}: {1}".Fmt(ex.GetType().Name, ex.Message));
                res.EndRequest(skipHeaders: true);
            });

this.ServiceExceptionHandlers.Add((httpReq, request, exception) =>
            {
                var logger = LogManager.GetLogger(GetType());
                logger.Error("Unhandled error in API.", exception);

                //call default SS exception handler
                return DtoUtils.CreateErrorResponse(request, exception);
            });  

这是我在调用上述Action时在Swagger Rest客户端上看到的内容的屏幕截图。

Exception on Swagger

1 个答案:

答案 0 :(得分:4)

The issue is due to being unable to serialize the ErrorResponse DTO into the unregistered "application/pdf" ContentType.

I've just added a fallback to use the Config.DefaultContentType for serializing errors in unregistered Content Types in this commit, available from v4.0.61 that's now available on MyGet.

A workaround for prior versions of ServiceStack is instead of using the [AddHeader] Request Filter Attribute, to instead set the Content-Type in the Service implementation just before you serialize, so any Exceptions are thrown before Response ContentType is set, e.g:

public class ErrorStream {}
public class ErrorStreamService : Service
{
    public Stream Any(ErrorStream request)
    {
        if (!IsValid(request))
            throw new NotImplementedException("Exception in Stream Response");

       base.Request.ResponseContentType = "application/pdf";

       return PdfAsStream(request);
    }
}

Which throws a Typed Exception when using a Service Client:

try
{
    var response = client.Get<Stream>(new ErrorStream());
    Assert.Fail();
}
catch (WebServiceException ex)
{
    Assert.That(ex.IsAny400());
    Assert.That(!ex.IsAny500());
    Assert.That(ex.ErrorCode, Is.EqualTo("NotImplementedException"));
    Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.MethodNotAllowed));
}

Also UncaughtExceptionHandlers is only for handling Exceptions thrown outside of a Service, exceptions that occur within a Service are instead handled by ServiceExceptionHandlers instead, but be careful when modifying the default Exception handling behavior as you can invalidate the typed Exception handling on the client.