无法在自定义 C# 异常中访问 StackTrace

Unable to access StackTrace in custom C# Exception

我最近尝试为我的 Web API 设置一个日志系统。我决定我要创建自定义异常 classes 可以抛出然后由我的 GlobalExceptionHandler 记录。但是,我在访问自定义异常对象的 StackTrace 时遇到了一些问题。

我设置了一个名为 LoggableException 的自定义异常 class,我将其用作我要记录到数据库的所有自定义异常的父 class。

    public class LoggableException : Exception
    {
        public LogEntity Log { get; set; }
        public string ResponseMessage { get; set; }

        public LoggableException(LogEntity _log, string _responseMessage) : base(_log.ExceptionMessage)
        {
            Log = _log;
            Log.Level = LogLevel.Warn;
            Log.Exception = GetType().Name;
            Log.StackTrace = StackTrace.Substring(0, 1000);

            ResponseMessage = _responseMessage;
        }
    }

这是我的自定义 LoggableExceptions 之一的示例:

    public class InvalidPassword : LoggableException
    {
        public InvalidPassword(string email) : base(new LogEntity()
        {
            ExceptionMessage = $"Invalid password. email: {email}",
            ResponseCode = (int) HttpStatusCode.Unauthorized
        }, $"Unknown email or incorrect password.")
        { }
    }

但是,似乎每当我抛出这些 LoggableExceptions 之一时,<System.NullReferenceException: Object reference not set to an instance of an object. 也会在 Log.StackTrace = StackTrace.Substring(0, 1000); 处抛出。我这样做是为了不在我的数据库中存储巨大的 StackTrace 字符串,但 StackTrace 始终为空。我假设如果我调用基本构造函数它会自动实例化 StackTrace,但我想我错了。谁能向我解释我在这里做错了什么?我对 C# 还是比较陌生。

NullReference 异常被抛出,因为您正在访问构造函数本身内部构建的实例的 StackTrace 属性。

你应该使用

 Log.StackTrace = StackTrace?.Substring(0, 1000);

 if(StackTrace!=null) Log.StackTrace=StackTrace.Substring(0, 1000);

而是确保 this.StackTrace 已经实例化

您应该注意当 StackTrace 长度小于 1000 个字符时可能抛出的 ArgumentOutOfRangeException

这已经很老了,但还没有发布实际的解决方案。我还想在每个新的自定义异常上自动创建一个系统日志(即使这不是“最佳实践”),这对我有用。

虽然 Stacktrace 尚未在您的构造函数中初始化,但您可以 create a new instance of StackTrace

public class LoggableException : Exception
{
    public LogEntity Log { get; set; }
    public string ResponseMessage { get; set; }

    public LoggableException(LogEntity _log, string _responseMessage) : base(_log.ExceptionMessage)
    {
        Log = _log;
        Log.Level = LogLevel.Warn;
        Log.Exception = GetType().Name;
        Log.StackTrace = (new System.Diagnostics.StackTrace()).ToString();
        if (Log.StackTrace.Length > 1000)
            Log.StackTrace = Log.StackTrace.Substring(0, 1000);

        ResponseMessage = _responseMessage;
    }
}

这应该可以满足您的要求。

唯一的问题是您的 LoggableException 构造函数也会在那里(第 0 帧)突然出现,但您始终可以循环所有帧来创建 Stactrace 字符串,根据需要格式化数据并跳过第 0 帧。