在客户端处理自定义ServiceStack异常的正确/最佳方法是什么?

时间:2013-11-06 01:18:42

标签: c# exception-handling servicestack

我正在尝试简化使用JsonServiceClient消耗ServiceStack REST服务的客户端应用程序中的错误处理。

我在服务器上抛出的自定义异常在ResponseStatus对象中被序列化,我可以看到抛出WebServiceException

但目前我必须检查我的异常类型,方法是将WebServiceException ErrorCode与我的异常类的类型名称相匹配。 (在共享的DTO课程中公开):

/** Current Method **/

try {

    client.Get(new RequestThatWillFail());

} catch(WebServiceException ex) {
    if(ex.ErrorCode == typeof(ValidationFailedException).Name)
        Console.WriteLine("Validation error");
    else if(ex.ErrorCode == typeof(UnauthorizedException).Name)
        Console.WriteLine("Not logged in");
    else if(ex.ErrorCode == typeof(ForbiddenException).Name)
        Console.WriteLine("You're not allowed to do that!");
    else
        throw; // Unexpected exception              
}

理想情况下,我希望JsonServiceClient包含一些辅助方法或可覆盖的转换函数,以便将WebServiceException转换为我已知的异常类型;这样我就可以用更传统的方式使用try ... catch

/** Ideal Method **/

try {

    client.Get(new RequestThatWillFail());

} catch(ValidationFailedException ex) { // (WebServiceException is converted)
    Console.WriteLine("Validation error");
} catch(UnauthorizedException ex) {
    Console.WriteLine("Not logged in");
} catch(ForbiddenException ex) {
    Console.WriteLine("You're not allowed to do that!");
}

更新(澄清)

  • 我有异常工作,我可以调试,并获得我需要的所有信息。
  • 但我希望最终能够捕获我自己的异常,而不是通用的WebServiceException
  • 我不打算在异常上扩展其他属性,最终方便的是不必在catch中执行大量typeof(MyException).Name == ex.ErrorCode

我希望能够为JsonServiceClient提供以下地图:

{ Type typeof(Exception), string ErrorCode }

即。像

这样的东西
JsonServiceClient.MapExceptionToErrorCode = {
    { typeof(BadRequestException), "BadRequestException" },
    { typeof(ValidationFailedException), "ValidationFailedException" },
    { typeof(UnauthorizedException), "UnauthorizedException" },
    { typeof(AnotherException), "AnotherException" }
    // ...
}

类似于服务器当前如何将异常映射到Http状态代码。

然后ThrowWebServiceException<TResponse>中的HandleResponseError<TResponse>JsonServiceClient可以在地图中查找ErrorCode,如果匹配,则返回该类型的新异常,传递WebServiceException作为参数,或者翻译属性。

但最终目标是抛出更可用的错误。如果没有匹配,请继续抛出WebServiceException

我会覆盖ThrowWebServiceException<TResponse>HandleResponseError<TResponse>但我不认为这是可能的。我不想建立自己的版本来提供这种功能。

我希望我已经解释过这个。

1 个答案:

答案 0 :(得分:3)

我的异常处理方法是在服务方面做Structured Error HandlingOverriding the default Exception handling中描述的内容。 我使用我的ServiceRunner并覆盖HandleException。 如果抛出我的API异常,那么我创建一个自定义响应。

       public override object HandleException(IRequestContext requestContext,T request, 
                                                   Exception ex)
    {
         APIException apiex = ex as APIException;    // custo application exception
        if (apiex != null)
        {
            ResponseStatus rs = new ResponseStatus("APIException", apiex.message);
            rs.Errors = new List<ResponseError>();
            rs.Errors.Add(new ResponseError());
            rs.Errors[0].ErrorCode = apiex.errorCode.ToString();               
            rs.Errors[0].FieldName = requestContext.PathInfo;

             rs.Errors[1].ErrorCode = apiex.detailCode.ToString(); 
            // create an ErrorResponse with the ResponseStatus as parameter
            var errorResponse = DtoUtils.CreateErrorResponse(request, ex, rs);

            Log.Error("your_message", ex);   // log only the the error
            return errorResponse;

        }
        else
            return base.HandleException(requestContext, request, ex);

    }

更新: 在客户端,我为服务调用和WebServiceException创建一个包装器, 我检查了ResponseStatus.Errors 。如果是我的错误代码,那么我会重新抛出异常。

   T ServiceCall<T>(string command, string rest_uri, object request)
    {
        try
        {   
                if (command == "POST")
                      return client.Post<T>(serverIP+rest_uri, request);

        }
        catch (WebServiceException err)
        {
           if (err.ErrorCode == "APIException" && err.ResponseStatus.Errors != null 
                          &&  err.ResponseStatus.Errors.Count > 0)
            {
                string  error_code = err.ResponseStatus.Errors[0].ErrorCode;
                string  path_info = err.ResponseStatus.Errors[0].FieldName;  
                string detail_error = err.ResponseStatus.Errors[1].ErrorCode; 

                 throw new  APIException(error_code,detail_error,path_info);           
            } 
        } finally {}
   }