我正在尝试简化使用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!");
}
更新(澄清)
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>
但我不认为这是可能的。我不想建立自己的版本来提供这种功能。
我希望我已经解释过这个。
答案 0 :(得分:3)
我的异常处理方法是在服务方面做Structured Error Handling和Overriding 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 {}
}