如何在Application Insights中自动展示自定义异常属性(无需额外捕获)
I've defined a custom exception like this:
public class InvalidStatusCodeException : Exception { public HttpStatusCode ReceivedStatusCode { get; set; } public string ApiUrl { get; set; } public InvalidStatusCodeException(HttpStatusCode receivedStatusCode, string apiUrl) { ReceivedStatusCode = receivedStatusCode; ApiUrl = apiUrl; } }
I throw it in some scenarios:
string url = "api/group/1/getAll"; var response = await _client.GetAsync(url); if (!response.IsSuccessStatusCode) throw new InvalidStatusCodeException(response.StatusCode, url);
When I catch and log it, I can only see the custom property values in the error message I construct:
catch(InvalidStatusCodeException status_ex) { string error = $"Invalid Status code for request: '{status_ex.ApiUrl}', received code: {status_ex.ReceivedStatusCode}"; log.LogError(status_ex, error, "InvalidStatusCode"); }
If I don't catch it at all and let it be logged automatically, I can't see these details at all. Is there a way to view these custom properties without having to explicitly catch the exception every time?
Answer
Great question! The core issue here is that default exception logging typically only includes the message, stack trace, and inner exception details—your custom properties aren't automatically picked up. Here are several clean ways to fix this without manual exception catching every time:
1. Override ToString() for your custom exception
By overriding the ToString() method, you can inject your custom property details directly into the exception's default string representation. Most logging frameworks use this method when outputting uncaught exceptions:
public class InvalidStatusCodeException : Exception { public HttpStatusCode ReceivedStatusCode { get; set; } public string ApiUrl { get; set; } public InvalidStatusCodeException(HttpStatusCode receivedStatusCode, string apiUrl) { ReceivedStatusCode = receivedStatusCode; ApiUrl = apiUrl; } public override string ToString() { return $"InvalidStatusCodeException: Received status code {ReceivedStatusCode} for API URL '{ApiUrl}'{Environment.NewLine}{base.ToString()}"; } }
Now, even if the exception propagates uncaught and gets logged automatically, your custom details will be included alongside the standard exception stack trace.
2. Populate the base Exception.Data dictionary
The base Exception class includes a Data dictionary designed for storing custom context. Many structured logging frameworks (like Serilog, NLog) automatically serialize and log the contents of this dictionary:
public class InvalidStatusCodeException : Exception { public HttpStatusCode ReceivedStatusCode { get; set; } public string ApiUrl { get; set; } public InvalidStatusCodeException(HttpStatusCode receivedStatusCode, string apiUrl) { ReceivedStatusCode = receivedStatusCode; ApiUrl = apiUrl; // Add properties to the built-in Data dictionary Data["ReceivedStatusCode"] = ReceivedStatusCode; Data["ApiUrl"] = ApiUrl; } }
This approach keeps your properties structured, making them easier to filter or query in log management tools later.
3. Use a custom log enricher (for structured logging)
If you're using a structured logging framework, you can create an enricher that automatically detects your custom exception and extracts its properties as structured log fields. For example, with Serilog:
First, create the enricher:
public class InvalidStatusCodeExceptionEnricher : ILogEventEnricher { public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { if (logEvent.Exception is InvalidStatusCodeException ex) { logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ReceivedStatusCode", ex.ReceivedStatusCode)); logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ApiUrl", ex.ApiUrl)); } } }
Then register it in your Serilog setup:
Log.Logger = new LoggerConfiguration() .Enrich.With<InvalidStatusCodeExceptionEnricher>() // Add other configuration (sinks, minimum level, etc.) .CreateLogger();
Now, every log entry that includes your InvalidStatusCodeException will have ReceivedStatusCode and ApiUrl as structured properties—no manual catching required.
4. Include details in the base exception message
A quick and straightforward option is to pass a detailed message to the base Exception constructor. This message will be included in the default log output for uncaught exceptions:
public class InvalidStatusCodeException : Exception { public HttpStatusCode ReceivedStatusCode { get; set; } public string ApiUrl { get; set; } public InvalidStatusCodeException(HttpStatusCode receivedStatusCode, string apiUrl) : base($"Invalid status code {receivedStatusCode} for API URL '{apiUrl}'") { ReceivedStatusCode = receivedStatusCode; ApiUrl = apiUrl; } }
This ensures your context is visible even with minimal logging setup, though it doesn't provide structured data like the other methods.
内容的提问来源于stack exchange,提问作者Oleg Sh

