克服 ABP 框架异常转换中的 ErrorInfo 限制

Overcoming ErrorInfo limitations in ABP Framework exception conversion

我为 ASP.NET 样板实现了自定义 IExceptionToErrorInfoConverter 以在 Web API 中转换自定义异常。

问题是ABP有严格的接口,必须return ErrorInfo类型:

ErrorInfo Convert(Exception exception);

问题是 ErrorInfo 结构不符合我的要求,所以我想有自己的错误 DTO。

有人知道如何绕过 ABP 异常转换吗?

你可以试试一招。可能是,当 Abp 创建 json 响应时,它会通过反射用它的 所有可用的 属性序列化错误,并将它与其他东西一起包装到 MvcAjaxResponse 对象中,即你可以尝试创建自己的 class,派生自 ErrorInfo 并将其替换为 IExceptionToErrorInfoConverter 实现:

[Serializable]
public class MyErrorInfo : ErrorInfo
{
    public string MyProperty1 { get; set; }
    public int MyProperty2 { get; set; }
}

public class MyExceptionToErrorInfoConverter : IExceptionToErrorInfoConverter
{
    public IExceptionToErrorInfoConverter Next { set { } }        

    public ErrorInfo Convert(Exception exception)
    {
        return new MyErrorInfo{ MyProperty1 = "test", MyProperty2  = 1};
    }
}

这是我的补充信息,感谢@slava-utesinov

确实在 ABP 内部,正如人们所怀疑的那样,在处理序列化 DTO 时使用 object,因此假设是可靠的。

来自 ABP 源的一些示例代码:

public static string ToJsonString(this object obj, bool camelCase = false, bool indented = false)
{ ... }

protected override JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
{ ... }

因此,在成功之后,我尝试 隐藏原始 ErrorInfo 成员 来解决问题。现在,知道 ABP 使用 Json.NET 我发现了 Conditional Property Serialization 的特性。按照惯例实现 bool ShouldSerialize[member name]() 我们可以指示序列化程序忽略 属性.

所以我得到了以下概念验证代码:

public class ErrorInfoEx : ErrorInfo
{
   public new string Details { get; set; }
   public bool ShouldSerializeDetails() { return false; }

   public ErrorInfoEx(int code, string message) : base(code, message) { }
   public string MyField { get; set; }
}

请注意,由于某些原因,您必须替换基础 class 实现以忽略基础 class 成员。

结果是 JSON,如您所见,没有 'details' 属性,但存在 'myField'。

{
    "success":false,
    "result":null,
    "error":
        {
            "myField":"123",

            "code":420,
            "message":"Validation failed",
            "validationErrors":
                [{
                    "message":"'Order Number' should not be empty.",
                    "members":["OrderNumber"]
                }]
        },
        "unAuthorizedRequest":false
}