【问题标题】:How get Detail of InnerException如何获取 InnerException 的详细信息
【发布时间】:2016-10-25 20:42:15
【问题描述】:

关于重复。我可以访问Message 属性,但不能访问Detail 属性,即使在调试期间我可以看到它是异常对象的一部分。所以问题是为什么不能访问Detail 属性。

我发现了一个异常。

catch (Exception ex)
{
    string msg = ex.InnerException.InnerException.Message;
    // say Exception doesnt have Detail property
    // string detail = ex.InnerException.InnerException.Detail; 
    return Json(new { status = "Fail", message = msg, detail: detail });
}

ex 什么都不说

ex.InnerException 显示相同的消息

ex.InnerException.InnerException. 最后是一些真实的消息,"db table duplicated key"

ex.InnerException.InnerException.Message 我可以收到消息。

但即使只有一个属性Detail,也无法获取详细信息"the guilty key"

  1. 那么我怎样才能得到详细信息呢?。
  2. 奖励:为什么必须深入InnerException 两次才能获得有意义的消息?

【问题讨论】:

  • 遍历异常列表并尝试转换为特定的异常类型,如果转换成功则读取详细信息。
  • This 是我使用的方法。诀窍是while (ex != null) { thisMsg = ex.Message; ex = ex.InnerException; }。这样,无论是 0 还是一堆,您都可以迭代所有内部异常。如何将所有消息连接到一个返回或单个消息中,这完全取决于您。
  • @L.B 可能你不是投票者,或者如果你是,你是他们中最好的,因为你留下了评论。 IMO 用户的声誉并不是拒绝投票的好理由。这是一个像其他问题一样的问题,看到这个问题有如此多的反对票真的很奇怪!也许用户是 C# 的初学者。
  • Getting all messages from InnerException(s)? 的可能重复编辑:已标记。至于他的第二个问题,重复的可能是here,但因为你不应该同时提出两个问题,所以我认为我不应该将其标记为两个问题的重复。
  • @L.B 不需要讽刺。如果您查看我的个人资料,我的更多代表来自 SQL 而不是 C#。另外,如果您看到我已经调试了代码并且找不到如何获取它。

标签: c# exception


【解决方案1】:

我认为现在最优雅的方法是使用C# 6 when keyword in a catch statement 和C# 7 is operator。

try
{
    //your code
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException pex)
{
    string msg = pex.Message;
    string detail = pex.Detail; 
    return Json(new { status = "Fail", message = msg, detail: detail });
}

【讨论】:

    【解决方案2】:
    1. 诀窍是识别引发的异常类型并将一般异常转换为正确的类型,然后您将可以访问该异常类型的扩展属性。

    例如:

    if (processingExcption is System.Data.Entity.Validation.DbEntityValidationException)
    {
        exceptionIsHandled = true;
        var entityEx = (System.Data.Entity.Validation.DbEntityValidationException)processingExcption;
        foreach (var item in entityEx.EntityValidationErrors)
        {
            foreach (var err in item.ValidationErrors)
                returnVal.Invalidate(SystemMessageCategory.Error, err.ErrorMessage);
        }
    }
    else if (processingExcption is System.Data.SqlClient.SqlException && ((System.Data.SqlClient.SqlException)processingExcption).Number == -2)//-2 = Timeout Exception
    {
        exceptionIsHandled = true;
        returnVal.Invalidate(SystemMessageCategory.Error, "Database failed to respond in the allotted time. Please retry your action or contact your system administrator for assistance.", 
            messageCode: Architecture.SystemMessage.SystemMessageCode.DBTimeout);
    }
    
    1. 您正在寻找的细节是 2 个内部异常深度这一事实是偶然的。根据异常被捕获和包装的次数,将决定您关心的异常的深度 - 您最好的办法是遍历异常堆栈以查找您希望处理的异常类型。

    【讨论】:

    • 谢谢 Theo,终于有东西可以用了。我开始为这么多的反对票感到难过。因此,即使在调试时我也可以看到 Detail 属性,直到我转换为其他东西才能访问?
    • 是的。详细信息可能特定于任何异常类型。您必须将其强制转换为该类型才能访问该属性。该 sn-p 来自递归异常检查,我必须从发生的实体框架验证异常中提取详细信息,然后用不同的异常类型包装。注意:只要有可能,最好不要catch(Exception),而是catch(System.Data.Entity.Validation.DbEntityValidationException),但是当异常被包装时,类型是错误的,所以你会被递归检查卡住。
    • 我找到了解决方案,但我无法捕获特定异常,仍然必须捕获通用异常。我怎么知道ex 的具体异常是什么?
    • 好的,我想我现在找到了类型;)
    【解决方案3】:

    参考我评论过的您自己的答案,您绝对应该更加防御,否则您可能会在 catch 子句中出现空引用异常。

    catch (Exception ex)
    {
        string Detail = string.Empty;
    
        while ( ex != null ) 
        {
            if ( ex is Npgsql.NpgsqlException )
            {
                // safe check
                Npgsql.NpgsqlException ex_npg = (Npgsql.NpgsqlException)ex;
                Details = ex_npg.Detail;
            }
            // loop
            ex = ex.InnerException;
        }
    
        // warning, Detail could possibly still be empty!
        return Json(new { status = "Fail", detail = Detail });
    }
    

    【讨论】:

      【解决方案4】:
      1. 您无法获得比此异常更多的详细信息

      在内部异常上显示真正的异常循环,直到它为空。然后你到达了第一个

      1. 异常是从源类或函数引发的,然后由上层类读取并抛出更多全局细节,因为源上没有错误处理

      【讨论】:

      • 1.但如图所示,该对象具有Detail 属性
      • 当然。但是没有更多的细节......这就是我的意思
      【解决方案5】:

      嗯,这很可悲,但内心的例外不是魔术棒。通常,它只是您调用的代码的作者将其作为 Exception 构造函数的第二个参数的对象。所以,一般的答案是:“没办法”。但是调试器有时会有所帮助:)。我会说 - 异常的调用堆栈通常更具描述性 InnerException。

      【讨论】:

        【解决方案6】:

        一个快速的解决方案是单击“快速监视”窗口中的“详细信息”属性。您的答案将在快速观看窗口顶部的“表达式”文本框中。例如,Postgres 重复详细信息的表达式为:

        ((Npgsql.PostgresException)ex.InnerException.InnerException).Detail
        

        【讨论】:

          【解决方案7】:

          这是我从 Postgres 异常中获取更多信息的函数

          catch (Exception ex)   {
                          // Get PGSQL exception info              
                          var msg = ExceptionMessage (ex);
          }
          
          public static string            ExceptionMessage            (Exception ex) {
                      string msg = ex.Message;
          
                      var pgEx = ex as PostgresException;
                      if (pgEx != null) { 
                          msg = pgEx.Message;
                          msg += pgEx.Detail != null ? "\n"+pgEx.Detail.ToStr() : "";
                          msg += pgEx.InternalQuery != null ? "\n"+pgEx.InternalQuery.ToStr() : "";
                          msg += pgEx.Where != null ? "\n"+ pgEx.Where : "";
                      }
          
                      return msg;
                  }
          

          【讨论】:

            【解决方案8】:

            感谢 Maciej 这个解决方案非常适合拦截 PostgreSQL 错误

            我仅对此进行了更正

            msg += pgEx.Detail != null ? "\n"+pgEx.Detail.ToStr() : "";
            msg += pgEx.InternalQuery != null ? "\n"+pgEx.InternalQuery.ToStr() : "";
            

            改为

            msg += pgEx.Detail != null ? "\n" + pgEx.Detail.ToString() : "";
            msg += pgEx.InternalQuery != null ? "\n" + pgEx.InternalQuery.ToString() : "";
            

            【讨论】:

              猜你喜欢
              • 2016-09-24
              • 1970-01-01
              • 1970-01-01
              • 2017-09-24
              • 2015-11-14
              • 2014-10-15
              • 1970-01-01
              • 1970-01-01
              • 2011-03-02
              相关资源
              最近更新 更多