I try to implement code for error handling from Newtonsoft Documentation
I am using the following JsonSerializerSettings
errors = new JsonErrors();
jsonSerializerSettings = new JsonSerializerSettings
{
Error = delegate (object sender, ErrorEventArgs args)
{
errors.Add(args.ErrorContext.Error.Message);
args.ErrorContext.Handled = true;
}
};
I use the following code to deserialize the response.
try
{
deserializedObject = JsonConvert.DeserializeObject(response, jsonSerializerSettings);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
If add some extra chars at the end of the response string i expect to catch deserialize exception but actually i see relevant error added to JsonErrors object.
Can i be sure that any error raised by de-serialization/serialization will be catched by JsonSerializerSettings mechanism.
Can i remove the try a catch in code?
In theory all exceptions should be caught and passed to the handler (other than exceptions that cannot be caught such as StackOverflowException.) If you go to the github source and search for IsErrorHandled you will see that all types of exception are caught, for instance here:
catch (Exception ex)
{
if (IsErrorHandled(null, contract, null, reader as IJsonLineInfo, reader.Path, ex))
{
HandleError(reader, false, 0);
return null;
}
else
{
// clear context in case serializer is being used inside a converter
// if the converter wraps the error then not clearing the context will cause this error:
// "Current error context error is different to requested error."
ClearErrorContext();
throw;
}
}
That being said, in practice there may be edge cases where this does not work. For instance, in a previous answer I noted that exceptions thrown from the OnSerializing event of the root object cannot be handled -- though this seems not to be reproducible in the current version (9.0) of Json.NET. But even in the current version, if an exception is thrown trying to create a contract for the root object, Json.NET will not catch and handle it. This could happen because of a buggy custom contract resolver, or because of a mistake in applying serialization attributes to the root object. For instance, trying to serialize or deserialize the following as the root object:
public class BadExtensionData
{
Dictionary<string, object> extensionData;
[JsonExtensionData]
public Dictionary<string, object> ExtensionData { set { extensionData = value; } }
}
will result in an unhandled exception:
Newtonsoft.Json.JsonException: Invalid extension data attribute on 'BadExtensionData'. Member 'ExtensionData' must have a getter.
Thus you may want to leave the outer try/catch just in case (and even report an issue for exceptions that cannot be handled).
Finally, do be aware that catching and swallowing all exceptions is considered bad practice.
After quick source code inspection I tend to say that following sentence is true:
If JsonSerializerSettings is proper (ie. without nasty null references and with configured error handler with Handled property set to true)
and input string is not null (only for deserialization), then try-catch block is redundant.
Related
I'm having trouble to get a status code from a HttpRequestException on netstandard 2.1 at the catch block. At the .NET Framework there is an extra property "StatusCode", but I can't find any similar for netstandard. Is there any alternative?
Thanks in advance.
I already tried to convert a HttpRequestException into a WebException. Catching a WebException does not trigger the catch.
As already mentioned in comments to your OP, the StatusCode property was introduced in .NET 5 and won't be available in .NetStandard. This means you have to "do it yourself".
You can include the status code value in the existing exception without having to create and maintain a new exception type by leveraging the Data dictionary like this (change the names to your liking):
public static class HttpResponseMessageExtensions
{
public static void MyEnsureSuccessStatusCode(this HttpResponseMessage httpResponseMessage)
{
try
{
httpResponseMessage.EnsureSuccessStatusCode();
}
catch (HttpRequestException ex) when (ex.SetStatusCode(httpResponseMessage.StatusCode))
{
// Intentionally left empty. Will never be reached.
}
}
}
public static class HttpRequestExceptionExtensions
{
private const string StatusCodeKeyName = "StatusCode";
public static bool SetStatusCode(this HttpRequestException httpRequestException, HttpStatusCode httpStatusCode)
{
httpRequestException.Data[StatusCodeKeyName] = httpStatusCode;
return false;
}
public static HttpStatusCode? GetStatusCode(this HttpRequestException httpRequestException)
{
return (HttpStatusCode?)httpRequestException.Data[StatusCodeKeyName];
}
}
Note the usage of an always-false exception filter there. This ensures modifying the original exception doesn't incur severe costs as it retains the original exception as is (it is never "caught" there)
You can then use the new extension instead of the original EnsureSuccessStatusCode to throw the exception:
// grab real response here
var response = default(HttpResponseMessage);
response.MyEnsureSuccessStatusCode();
And you can grab the status code from the exception object using the GetStatusCode extension on whoever is catching the exception upstream.
If you want to make this even more robust, and ensure that you only call GetStatusCode on an exception that was thrown using the custom overload, you can also add a "marker" value in the dictionary to indicate that it was thrown using the extension and act on that (for example, throw an InvalidOperationException saying the method can only be used in conjunction with MyEnsureSuccessStatusCode).
This might be a broad question, but recently I ahve wondered about the following: In our C# backend we have many places that wrap some code in a try/catch block, specifically calls to external WcF services. Some of these calls are crucial for the application so in the catch block we log the error and rethrow, like:
catch(Exception ex)
{
_logger.Error("Some good error message");
throw ex;
}
On the other hand there are services we allow to fail, but we still want to log the error, so they look like:
catch(Exception ex)
{
_logger.Error("Some good error message");
}
Now reading the code of team members I can not be sure if they forgot to throw or if this is the intended behaviour.
Q: Is there a way, resp. what is the default way, to explicitly NOT rethrow (without including a comment in the code).
I have considered something like this:
catch(Exception ex)
{
_logger.Error("Some good error message");
NotThrowingHereOnPurpose();
}
// ...
// and further below a private method
// ...
private void NotThrowingHereOnPurpose(){}
One approach that may be useful here is to change the way of invoking the code that you explicitly allow to fail in such a way that it does not look like a try/catch block at all.
For example, you could write a helper method that does error reporting, and call it with actions expressed as lambdas:
void InvokeFailSafe(Action action, Action<Exception> onFailure = null) {
try {
action();
} catch (Exception e) {
if (onFailure != null) {
onFailure(e);
}
}
}
Now instead of try/catch you would write this:
InvokeFailSafe(
() => {
... The code that may fail
}
, exception => _logger.Error("Some good error message: {0}", exception)
);
or like this, if you don't want anything logged:
InvokeFailSafe(
() => {
... The code that may fail
}
);
If you code things this way, there would be no doubts about a missing throw statement.
It's an opposite solution to dasblinkenlight's answer. Instead of notifying others that the exception mustn't be rethrown it would say that it must be.
If you only want to log it then use the Error method as usual. Otherwise, you can write an extension method for your logger to log and throw exceptions.
The method would take the catched exception and rethrow it using the ExceptionDispatchInfo class. The ExceptionDispatchInfo is used to rethrow the exception with the original stack trace information and Watson information. It behaves like throw; (without the specified exception).
public static void ErrorAndThrow(this ILogger logger, string message, Exception exception)
{
var exceptionInfo = ExceptionDispatchInfo.Capture(exception);
logger.Error(message);
exceptionInfo.Throw();
}
And use it this way:
try
{
}
catch (Exception ex)
{
// ex would be rethrown here
_logger.ErrorAndThrow("Some good error message", ex);
}
Q: Is there a way, resp. what is the default way, to explicitly NOT
rethrow (without including a comment in the code).
Ideal way would be not to catch a generic exception. Now, to throw or not that entirely depends on your case. You need to understand that Exception handling is used when you know what to do in case an exception occurs. So, only specific exceptions should be handled. Catching exceptions without knowing what you are catching will change the behavior of your application.
Now reading the code of team members I can not be sure if they forgot
to throw or if this is the intended behaviour.
This is something the author of the code can explain to you. But here is a learning to take from this. Your code should be self explanatory. In specific cases where you are unable to express yourself with the code, add a meaningful comment.
You can check this link for better understanding.
I actually found another way that kind of includes what other have suggested here, but uses a built in feature: exception filters. I was free to modify the example given in here to illustrate this:
public void MethodThatFailsSometimes()
{
try {
PerformFailingOperation();
}
catch (Exception e) when (e.LogAndBeCaught())
{
}
}
and then one could have two extension methods on Exception, say LogAndBeCaught and LogAndEscape like so:
public static bool LogAndBeCaught(this Exception e)
{
_logger.Error(#"Following exception was thrown: {e}");
return true;
}
public static bool LogAndEscape(this Exception e)
{
_logger.Error(#"Following exception was thrown: {e}");
return false;
}
Is there a way to override the message of an exception?
I don't want to make a custom exception but to override the message of an existing exception.
For example:
Every time when a ArgumentOutOfRangeException is thrown, I'd like it to contain my message instead of the default one.
Is it possible?
For exceptions you're throwing, you can just pass the message in to the constructor:
throw new ArgumentOutOfRangeException("name", "My custom message");
Note that here, name is the name of the parameter that caused the problem. In C# 6, you should use the nameof operator to make this refactoring-safe:
public void Foo(int x)
{
if (x > 10)
{
throw new ArgumentOutOfRangeException(nameof(x), "That's too big");
}
}
You can't modify the message of an exception thrown by other code, but you can catch the exception and rethrow another one:
try
{
...
}
catch (FooException e)
{
// Keep the original exception
throw new BarException("Some message", e);
}
I would try to avoid doing this too much though. If you're considering showing exception messages to users, I would generally shy away from that - they're really aimed at developers. As an example, the ArgumentOutOfRangeException you suggested should generally indicate a bug in your code rather than some external condition (like a network failure or whatever) - the user isn't going to be able to do anything about that bug; it's something you should fix. A network failure or something similar is at least more reasonable for the user to take action about, but frankly it's often not going to be clear what the chain of events is.
The Exception.Message property is declared read-only, so no, you cannot change the Message of a pre-existing Exception object. (The same applies to derived exception types.)
But you can set the message text of an exception you're throw-ing yourself: usually, you pass the message text to the exception constructor:
throw new ArgumentException("Frobbled arguments are not accepted", paramName: …);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When you define your own exception types, you should follow this protocol; see the section at the end of this answer.
You want to change an existing exception object's Message — Alternatives:
Catch the original exception and derive a new exception from it that is identical except for the message:
…
catch (ArgumentException ex)
{
throw new ArgumentException("New message text", paramName: ex.ParamName);
}
This is in general not a terribly good idea, because you might lose state data contained in ex (such as its stack trace and InnerException). But it might work just fine in this scenario.
Wrap the exception in a new exception so that it becomes the InnerException:
…
catch (ArgumentException ex)
{
throw new ArgumentException("New message text", innerException: ex);
}
This is better, because all the original exception's state is preserved. However, in the particular case of ArgumentException it is not obvious at all that the actual exception information is contained in the InnerException.
How to make sure your own exception classes allow setting the message et al.:
When you define a new exception type, it's important for the reasons mentioned above to define constructors that accept a message text and/or an inner exception. So a custom exception class would have at least these constructors:
class MyCustomException : Exception
{
public MyCustomException() : base() { }
public MyCustomException(string message) : base(message) { }
public MyCustomException(string message, Exception innerException) : base(message, innerException) { }
public MyCustomException(string message) : base(message) { }
}
You can use try .. . catch
try
{
//Code here regarding array indexing
}
catch (ArgumentOutOfRangeException ex)
{
throw new ArgumentOutOfRangeException("exception", "New Custom Message");
//Or show new message
MessageBox.Show("Your custom Message");
}
I want a central place to extract information from an exception, set all the information I need to its message parameter and then rethrow that information as an Exception of the same type.
The better solution probably would be to do this at the place where the exception is finally being handled (and its message logged), but.. I have control over the place throwing the exception, and not over the place that receives the exception and only logs its Message content.
Apart from that design decision and given that message is a readonly property, I would have (?) to create a new Exception object in some way, is there a way to make the new exception object the same type as the original one?
Here is my code, which does not compile - it stumbles over the throw line (where I try to dynamically cast the object).
public static void RethrowExceptionWithFullDetailInMessage(string msg, Exception ex)
{
Exception curEx = ex;
int cnt = 0;
while (curEx != null)
{
msg += "\r\n";
msg += cnt++ + " ex.message: " + curEx.Message + "\r\n";
msg += "Stack: " + curEx.StackTrace;
curEx = curEx.InnerException;
}
object newEx = Convert.ChangeType(new Exception(msg), ex.GetType());
throw (ex.GetType())newEx;
}
Does this
throw (Exception)newEx;
preserve the type? (It compiles.)
Does the Convert.ChangeType make sure I get an Exception of the correct type?
What you are trying to do here is not as easy as it seems and there are lots of pitfalls to consider.
Remember, that Convert.ChangeType() will convert one type to another (assuming such a path exists, like converting a string to an int for example). Most exceptions wont do this (Why would they?)
IN order to pull this off, you would have to examine the exception type at runtime with the GetType() method and locate a constructor that has requirements you can satisfy and invoke it. Be careful here, since you don't have control over how all exceptions are defined there is no guarantee you will have access to "standard" constructors.
That being said, if you feel like being a rule breaker you could do something like this...
void Main()
{
try
{
throw new Exception("Bar");
}
catch(Exception ex)
{
//I spit on the rules and change the message anyway
ex.GetType().GetField("_message", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ex, "Foo");
throw ex;
}
}
You could do this to dynamically call the constructor of the exception type:
object newEx = Activator.CreateInstance(ex.GetType(), new object[] { msg });
Your original code would fail at runtime, because for Convert.ChangeType towork, the exception type would have to implement IConvertible and support conversion to the other exception type, which i doubt.
May be it's a bit late, but would this work for you?
catch (Exception ex)
{
throw new Exception("New message", ex);
}
You can change the exception message via reflection like this...
Exception exception = new Exception("Some message.");
var type = typeof(Exception);
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var fieldInfo = type.GetField("_message", flags);
fieldInfo.SetValue(exception, message);
So you can create an extension method...
namespace ExceptionExample
{
public static class ExceptionExtensions
{
public static void SetMessage(this Exception exception, string message)
{
if (exception == null)
throw new ArgumentNullException(nameof(exception));
var type = typeof(Exception);
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var fieldInfo = type.GetField("_message", flags);
fieldInfo.SetValue(exception, message);
}
}
}
And then use it...
...
using static ExceptionExample.ExceptionExtensions;
public class SomeClass
{
public void SomeMethod()
{
var reader = AnotherClass.GetReader();
try
{
reader.Read();
}
catch (Exception ex)
{
var connection = reader?.Connection;
ex.SetMessage($"The exception message was replaced.\n\nOriginal message: {ex.Message}\n\nDatabase: {connection?.Database}");
throw; // you will not lose the stack trace
}
}
}
You have to keep in mind that if you use "throw ex;" the stack trace will be lost.
To avoid this you must use "throw;" without the exception.
Supplemental comment.
These all work in supplementing the exception message, but I found that using "throw" did NOT preserve the StackTrace - the last trace pointed to the actual "throw" statement (dropping the root cause location).
From discussions elsewhere, it's clear there are some circumstances that throw doesn't preserve due to CLR stack limitations
Throw and preserve stack trace not as expected as described by Code Analysis
Solution: dump the StackTrace in each exception (e.g. and add to the error message) and/or dump to logging
So, I have a list containing a custom class, MyClass
MyClass has properties, which can be null (but aren't meant to be).
When this class is sorted, using a custom sorter, where the sorter accesses this null property and throws an exception, the exception is considered unhandled, even though there is a try-catch block around the sort method.
Now for some reason the exception still gets written to the console, which is what the exception handler is doing.
I have a real application with this same issue, causing my unit tests to fail, even though the exception is handled correctly and I cannot explain this.
So I have attached some sample code to explain myself better, run this from VS.
Updated Code
Results:
System.InvalidOperationException
Failed to compare two elements in the array.
Done!
So it seems to be handling my custom exception, and throwing its own?
using System;
using System.Collections.Generic;
using System.Data;
namespace TestSortException
{
class Program
{
static void Main()
{
try
{
var list = new List<MyClass>
{
new MyClass("1"),
new MyClass(null),
new MyClass("fdsfsdf")
};
list.Sort(new MyClassSorter());
}
catch(Exception e)
{
Console.WriteLine(e.GetType());
Console.WriteLine(e.Message);
}
Console.WriteLine("Done!");
Console.ReadLine();
}
}
class MyClassSorter : IComparer<MyClass>
{
public int Compare(MyClass x, MyClass y)
{
// try
// {
if (x.MyString == y.MyString)
return 0;
// Unhandled??? Exception here
if (x.MyString.Length > y.MyString.Length)
return 1;
return -1;
// }
// catch (Exception)
// {
// return -1;
// }
}
}
class MyClass
{
private string _myString;
public string MyString
{
get
{
if (_myString == null) throw new DataException("MyString is Null");
return _myString;
}
}
public MyClass(string myString)
{
_myString = myString;
}
}
}
There's a try/catch block round the Sort method, yes - and that catch block catches the exception. In other words, Sort throws an exception and your catch block catches it. It doesn't propagate out beyond Main - so "Done!" is printed.
This is exactly what I'd expect. In what way is it "unhandled" in your experience? Were you expecting Sort not to throw the exception? It needs to do something to indicate the failure to compare two elements, and this seems to be the most appropriate course of action.
In what way are your unit tests failing? Are you deliberately giving them invalid data? How do you want your comparison code to react to invalid data? If it should ignore it (and return a comparison based on another property), then you should actively check the property rather than letting an exception propagate. In most cases I'd rather allow the exception if this indicates that there's a bug earlier on though.
EDIT: Based on your other comments, it sounds like you're doing the appropriate thing, letting the exception bubble up - but it's not clear in what way you're seeing the exception not be handled.
If you're running in the debugger, it may be breaking on the exception being thrown, but that doesn't mean it won't be handled. Try either changing your exception settings or running without the debugger.
EDIT: Yes, Sort will catch the exception and throw an InvalidOperationException instead - but you can use the InnerException property of that exception to get hold of the original one. It's unfortunate that the documentation doesn't specify this :(
For example, when it checks that string "1" isn't equal to null. But it wants then to compare lengths of "1" string and null => which is impossible.
I assume you work with .Net Framework 4.0. The new thing there is that a NullRefenrenceException can not be caught any more (similar to OutOfMemory exception).