无法控制异常对象的所有内容(位置不可用)

Unable to control the every content of an Exception object (location not available)

出于测试目的,我有一种手动导致应用程序崩溃的方法。它按预期工作,并且自定义错误页面显示如我所愿。但是,我注意到虽然 outer 异常(即 the 异常)提供了位置信息(即 Api.Controllers.UtilController.Poof () in UtilController.cs, line 58 on the last line below), the inner one doesn't (stating but Unknown location,而我被引导相信 otherwise)。完整呈现的错误信息内容如下

Exception: There are no details but the error code.
GUID: 77ad89f7-7220-43b6-8fe9-d473e18ff07b
See outer text for general info.
Unknown location

Exception: This is a crash test invoked @ 07:21:15.
See inner exception for details.
Api.Controllers.UtilController.Poof() in UtilController.cs, line 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;
}

我已阅读 exception page in WebAPI and the general exception object (including the properties such as Source and TargetSite for the InnerException) 的文档。我觉得我理解了内容,但事实并非如此。研究投入的努力,我需要帮助澄清以上三项。

这里的主要问题是只有一个例外实际上是 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;
        }
    }
}

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

Where are those location info strings located in the exception object?

通常在StackTrace

When/how do they get assigned?

当抛出异常时,它们会在 运行 时间填充。

The common language runtime (CLR) updates the stack trace whenever an exception is thrown in application code (by using the throw keyword). If the exception was rethrown in a method that is different than the method where it was originally thrown, the stack trace contains both the location in the method where the exception was originally thrown, and the location in the method where the exception was rethrown. If the exception is thrown, and later rethrown, in the same method, the stack trace only contains the location where the exception was rethrown and does not include the location where the exception was originally thrown.

引用Exception.StackTrace Property

Can I alter them and if so how?

Reference

Notes to Inheritors

The StackTrace property is overridden in classes that require control over the stack trace content or format.

By default, the stack trace is captured immediately before an exception object is thrown. Use StackTrace to get stack trace information when no exception is being thrown.

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

自定义异常

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

引用Implementing custom exceptions