1

我有一种手动导致应用程序崩溃以进行测试的方法。它按预期工作,并且自定义错误页面按我想要的方式显示。但是,我注意到虽然外部异常(即异常)提供了有关位置的信息(即UtilController.cs 中的 Api.Controllers.UtilController.Poof(),下面最后一行的第 58 行),但内部异常却没有(说明但位置未知,而我被引导相信其他情况)。呈现的错误信息的完整内容如下。

例外:没有详细信息,只有错误代码。
GUID:77ad89f7-7220-43b6-8fe9-d473e18ff07b
有关一般信息,请参阅外部文本。
位置不明

例外:这是@ 07:21:15 调用的碰撞测试。
有关详细信息,请参阅内部异常。
UtilController.cs 中的 Api.Controllers.UtilController.Poof(),第 58 行

我知道,由于内部异常只是实例化,而不是实际抛出,因此没有它的起源位置。我想将内部异常提供的位置文本更改为自定义内容。

调查对象的内容后,我发现只有两个属性似乎可能用于该目的 - SourceTargetSite。但是,设置这些值并没有带来任何值的变化(保持null,尽管不是只读的),所以我得出结论它们会以某种方式被覆盖。即使在调用 throw 之后,我也没有找到与任何位置对应的字符串值的字段。

public ActionResult Poof()
{
  string occasion = DateTime.Now.ToString("HH:mm:ss");
  string message = "This is a crash test invoked @ " + occasion + "."
    + "\nSee inner exception for details.";
  string details = "There are no details but the error code."
    + "\nGUID: " + Guid.NewGuid()
    + "\nSee outer text for general info.";

  Exception innerException = new Exception(details);
  innerException.Source = "Location as referred below.";
  // innerException.TargetSite = new DynamicMethod(...);
  Exception exception = new Exception(message, innerException);

  throw exception;
}
  • 这些位置信息字符串位于异常对象中的什么位置?
  • 他们何时/如何被分配?
  • 我可以更改它们吗?如果可以,如何更改?

我已经阅读了 WebAPI 中异常页面的文档和一般异常对象(包括InnerExceptionSourceTargetSite属性)。我觉得我明白其中的内容,但事实证明并非如此。投入研究的努力,我需要帮助澄清以上三项。

4

1 回答 1

1

这里的主要问题是实际上只有一个例外是thrown.

外部异常有一个位置,因为它是thrown

内部异常已创建并添加到外部异常,但内部异常不是抛出和捕获的异常。因此,运行时不会填充任何位置信息。

例如下面的测试示例

[TestClass]
public class MyTestClass {
    [TestMethod]
    public void MyTestMethod() {
        string occasion = DateTime.Now.ToString("HH:mm:ss");
        try {
            string details = "There are no details but the error code." + "\nGUID: " + Guid.NewGuid() + "\nSee outer text for general info.";
            Exception innerException = new Exception(details);
            innerException.Source = "Location as referred below.";
            throw innerException;
        } catch (Exception e) {
            string message = "This is a crash test invoked @ " + occasion + "." + "\nSee inner exception for details.";
            Exception exception = new Exception(message, e);
            throw exception;
        }
    }
}

运行测试时显示以下消息

Result StackTrace:  
at UnitTestProject.tests.MyTestClass.MyTestMethod() in C:\...\UnitTest1.cs:line 33
--- End of inner exception stack trace ---
    at UnitTestProject.tests.MyTestClass.MyTestMethod() in C:\...\UnitTest1.cs:line 37
Result Message: 
Test method UnitTestProject.tests.MyTestClass.MyTestMethod threw exception: 
System.Exception: This is a crash test invoked @ 20:34:49.
See inner exception for details. ---> System.Exception: There are no details but the error code.
GUID: 2a9bd143-6647-4774-9ea4-615d7f1d2f9f
See outer text for general info.

如果测试改写如下

[TestClass]
public class MyTestClass {
    [TestMethod]
    public void MyTestMethod() {
        try {
            Core();
        }catch(Exception ex) {
            var temp = ex; //<-- PUT BREAKPOINT HERE
        }
    }

    private static void Core() {
        string occasion = DateTime.Now.ToString("HH:mm:ss");
        try {
            string details = "There are no details but the error code." + "\nGUID: " + Guid.NewGuid() + "\nSee outer text for general info.";
            Exception innerException = new Exception(details);
            innerException.Source = "Location as referred below.";
            throw innerException;
        } catch (Exception e) {
            string message = "This is a crash test invoked @ " + occasion + "." + "\nSee inner exception for details.";
            Exception exception = new Exception(message, e);
            throw exception;
        }
    }
}

并且经过调试,捕获的异常和内部异常都会包含所有相关内容。在内部异常中包含自定义源。

这些位置信息字符串位于异常对象中的什么位置?

通常在StackTrace

他们何时/如何被分配?

当抛出异常时,它们由运行时填充。

每当在应用程序代码中引发异常时(通过使用 throw 关键字),公共语言运行时 (CLR) 都会更新堆栈跟踪。如果在与最初引发异常的方法不同的方法中重新引发异常,则堆栈跟踪包含最初引发异常的方法中的位置以及重新引发异常的方法中的位置。如果抛出异常,之后又重新抛出,在同一个方法中,堆栈跟踪只包含再次抛出异常的位置,不包括最初抛出异常的位置。

引用Exception.StackTrace 属性

我可以更改它们吗?如果可以,如何更改?

参考

继承人须知

StackTrace 属性在需要控制堆栈跟踪内容或格式的类中被覆盖。

默认情况下,堆栈跟踪是在抛出异常对象之前立即捕获的。当没有抛出异常时,使用 StackTrace 获取堆栈跟踪信息。

您可以考虑创建一个自定义派生异常,该异常检查基本堆栈跟踪以在返回堆栈跟踪之前进行所需的更改。

自定义异常

public override StackTrace {
    get {
        string original = base.StackTrace;
        
        string result = //...altered message
        
        return result;
    }
}

参考实现自定义异常

于 2020-06-27T00:52:51.907 回答