I got this class which raises same type of exception, how do i capture this exception and display appropriate error message. Here is what i do now.
public bool ChangePassword(oldPassword,newPassword)
{
if(oldPassword != savedInDatabase)
{
throw new ArgumentException("Your old password is not same as one saved in our database")
}
if(string.IsNullOrEmpty(oldPassword) || string.IsNullOrEmpty(newPassword))
{
throw new ArgumentException("Your old or new password is empty of null");
}
}
and i do the below,
try
{
}
catch(ArgumentException ex)
{
if(ex.Message.contains("Your old or"))
{
messagebox.show("Either your old or new password is empty or null")
}
...
}
Your example does not really justify custom exceptions. I say just display the original message.
However, if you really want to go down the path of custom exceptions, then another option is to create a single custom exception that takes an enum with all the different options, like such:
public class PasswordException : Exception
{
public PasswordException(PasswordResult result) : base() { }
public PasswordException(PasswordResult result, string message) : base(message) { }
public PasswordException(PasswordResult result, string message, Exception innerException) : base(message, innerException) { }
}
public enum PasswordResult
{
Success = 0,
PasswordMismatch,
PasswordEmpty,
// and so forth
}
You might consider throwing different exception types. If you wished to stick with the library exception types an ArgumentNullException would be appropriate if the old or new password is null or empty. Alternatively you may consider defining your own exception types with a more specific error (perhaps similar to FaultExceptions in WCF), or including a resource identifier in your custom exception (to ensure I18N compatible):
public class ResourceableException : Exception
{
public string ResourceKey { get;set; }
}
Then used like so:
try { ... }
catch (ResourceableException e)
{
messagebox.Show(ResourceManager.GetResource(e.ResourceKey));
}
You can create custom exceptions like this:
public class PasswordEmptyOrNullException : Exception
{
public PasswordEmptyOrNullException(string message)
: base(message)
{
}
}
public class OldPasswordNotFoundException : Exception
{
public OldPasswordNotFoundException(string message)
: base(message)
{
}
}
They can then be used like this:
throw new PasswordEmptyOrNullException("A message");
Then you can handle them in a try catch statement like this:
try
{
}
catch (PasswordEmptyOrNullException ex)
{
// Do stuff
}
catch (OldPasswordNotFoundException ex)
{
// Do stuff
}
So you can handle different types of exceptions in different ways. Hope that's what you were looking for.
Related
Question
I am currently implementing a UOW pattern and have come upon a weird behaviour for exception handling, which is hindering my progress.
My UOW structure looks the following:
public abstract class UnitOfWork : IDisposable {
public virtual void Save() {
if (_madeAction) ThrowInvalidCall();
_madeAction = true;
}
public virtual void Cancel() {
if (_madeAction) ThrowInvalidCall();
_madeAction = true;
}
public virtual void Dispose() {
if (!_madeAction) {
Cancel();
throw new UnitOfWorkAborted("Unit of work was aborted and automatically rolled back!");
}
}
private bool _madeAction = false;
private void ThrowInvalidCall() => throw new InvalidOperationException($"{nameof(Save)} or {nameof(Cancel)} can only be called once in a unit of work!");
}
[Serializable]
public class UnitOfWorkAborted : Exception {
public UnitOfWorkAborted() { }
public UnitOfWorkAborted(string message) : base(message) { }
public UnitOfWorkAborted(string message, Exception inner) : base(message, inner) { }
}
public interface IUnitOfWorkFactory {
UnitOfWork CreateNew();
}
I am expecting to use this UOW as follows:
try {
using (var uow = uowFactory.CreateNew()) {
// Do some operation
throw new InvalidCastException(); // Oh, something went wrong.
uow.Save();
}
} catch (UnitOfWorkAborted ex) {
// Handle exception
}
The problem obviously is, that the excpetion will never be handled by my try/catch clause as it only handles UnitOfWorkAborted which is only thrown after the InvalidCastException.
My question is, is there any way I can use my UOW how I expect it to work? (I'd like to replicate this behaviour -> TransactionScope)
I want to keep the code for creating a UOW and managing it as simple as possible.
If possible, I would love to even have the actual exception as the inner exception of UnitOfWorkAborted.
Observations/Attempts
1. Instead of catching the UnitOfWorkAborted I can catch all Exceptions and cast it to UnitOfWorkAborted.
try {
using (var uow = uowFactory.CreateNew()) {
throw new InvalidCastException();
uow.Save();
}
} catch (Exception ex) {
UnitOfWorkAborted uowEx = ex as UnitOfWorkAborted;
if (uowEx is null) throw ex;
// Handle exception
}
Cons:
I will need to cast the exception to UnitOfWorkAborted and this adds code that should be avoidable because:
What is try/catch then even for when not for specifying which exception to handle? This approach just feels.. ugh.
2. Add a catch clause for Exception.
try {
using (var uow = uowFactory.CreateNew()) {
throw new InvalidCastException();
uow.Save();
}
} catch (UnitOfWorkAborted ex) {
// Handle exception
} catch (Exception ex) {
throw ex;
}
I discovered this through experimentation, it works perfectly fine. Would it be possible to get a side-explanation on the details for why this works, I would be incredibly interested to know. Either way, the syntax is incredibly misleading, even worse than with the first attempt, and this is no option of course, just, look at it.
Are these two attempts really my only options on solving this problem?
I ended up using the callback method suggested by Jeremy Lakeman in the comments, which ended up working perfectly fine, with the bonus of catching inner exceptions.
Here What I want to do, but do not know if it will work or if there is a better way:
if (condition1){
try {
Block1;
}
} else if (condition2){
try {
Block2;
}
}
catch(ExceptionType1 ex) { process;}
catch(ExceptionType2 ex) { process;}
catch(Exception) {throw;}
So is that the best way this could be done?
This can do what you want.
try {
if (condition1) {
Block1;
} else if (condition2) {
Block2;
}
}
catch(ExceptionType1 ex) { process;}
catch(ExceptionType2 ex) { process;}
catch(Exception) {throw;}
If not, try to put a clear detailed example.
There is no syntax to support exactly, but you might be able to get a similar effect by defining exception classes, and purposely throwing those exceptions in block1 and block2, either through separate try/catches or if/conditonal statements (checking for null, "", etc.)
Here's an example of an exception class behind defined, taken from here
[Serializable()]
public class InvalidDepartmentException : System.Exception
{
public InvalidDepartmentException() : base() { }
public InvalidDepartmentException(string message) : base(message) { }
public InvalidDepartmentException(string message, System.Exception inner) : base(message, inner) { }
// A constructor is needed for serialization when an
// exception propagates from a remoting server to the client.
protected InvalidDepartmentException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
In the logic that you want to throw the exceptions in, you just need to define and throw the Exception class you defined. This can be done in a separate catch block, as well
System.ArgumentException argEx = new System.ArgumentException("Index is out of range", "index", ex);
throw argEx;
I'm not sure what you try to achieve with your structure in detail. But I see currently no issue in wrapping the whole statement block into a single try-block #AbdelAzizAbdelLatef mentioned and catch different exception types.
Maybe you can think about, to move your both code blocks (Block1 & Block2) into own functions/methods and perform a specific exception handling there and maybe returning some status code from each new block function. This would be a more clean code approach.
I cannot find a definitive answer, and well the MS docs are not the greatest so here goes to finding an answer versus being cast into down vote hell.
Consider this simple code:
try
{
if (errMessage.Contains(EXCEPTIONCOMPARISONMESSAGE))
{
//do stuff;
}
}
catch (Exception ex)
{
eventLog.WriteEntry("isAbleConvertToPDF: " + ex.Message, EventLogEntryType.Error);
}
My question is will ex.Message ever be an empty string or NULL? I think NOT, but I cannot find a definitive documented answer.
Looking for documentation to back up the answer given too please.
It's certainly possible - a custom exception (one that inherits from Exception) could return a null or empty string.
The Exception constructor also takes a message as a parameter, which could be an empty string.
There is nothing in the interface contract to indicate that the message can never be empty or null, so you should assume that it could be empty or null.
Here's an example, filling in your example code:
try
{
if (errMessage.Contains(EXCEPTIONCOMPARISONMESSAGE))
{
throw new MyEvilException();
}
}
catch (Exception ex)
{ V--------V this will be null
eventLog.WriteEntry("isAbleConvertToPDF: " + ex.Message, EventLogEntryType.Error);
}
private class MyEvilException : Exception
{
public override String Message
{
get
{
return null;
}
}
}
Exception is base class for other exceptions where Message property is marked as virtual.
Which mean that Message can be empty string or null, because every derived class can override it.
However actual implementation of Message in Exception class looks like
public virtual String Message
{
get
{
if (_message == null)
{
if (_className==null)
{
_className = GetClassName();
}
return Environment.GetResourceString("Exception_WasThrown", _className);
}
else
{
return _message;
}
}
}
So you can see from above, that null will never be returned from Exception base class, but empty string will be returned when throw new Exception(string.Empty);
We have an exceptions library that is expected to be used over several solutions. We have several custom exception types contained within this library.
The question that has arisen: If we want to align error messages being used in these exceptions, what is the best practise way to accomplish this? For this question, assume that there are 3 or 4 methods across the solutions who want to throw these types of exceptions.
Let's take an example:
public class CustomException : Exception
{
// You can assume that we've covered the other default constructors for exceptions
public CustomException(string message)
: base(message)
{
}
}
The work we want to replace:
public void DoWork()
{
Guid id = Guid.NewGuid();
// ...
throw new CustomException(string.Format("The guid was: {0}.", id));
}
Our current ideas
1/ Define a new constructor that accepts a guid that defines the error message:
const string GuidMessageTemplate = "The guid was: {0}.";
public CustomException(Guid id)
: base(string.format(GuidMessageTemplate, id))
{
}
public void DoWork()
{
Guid id = Guid.NewGuid();
// ...
throw new CustomException(id);
}
2/ Allow each solution to define exception builder classes/methods that instantiate the consistent exceptions
public class ExceptionBuilder()
{
const string GuidMessageTemplate = "The guid was: {0}.";
public CustomException BuildCustomException(Guid id)
{
return new CustomException(string.format(GuidMessageTemplate, id));
}
}
public void DoWork()
{
Guid id = Guid.NewGuid();
// ...
var exception = BuildCustomException(id);
throw exception;
}
3/ Another option?
Use first approach. Your exception should encapsulate building error message. Via constructor exception should recieve only context specific information from outside world.If your exception receive full error message via constructor, then client can create an instance of your exception as follows:
class InvalidEmailException : Exception
{
public InvalidEmailException(string message) : base(message)
{}
}
client code:
void ClientMethod()
{
throw new InvalidEmailException(String.Format("GUID {0} is wrong", Guid.NewGuid()));
}
But wait, I expect Email in this exception!
Approach with exception builder is over engineering, just use first approach :)
I find myself writing some methods where there is a code path that should never happen. Here is a simplified example:
double Foo(double x) {
int maxInput = 100000;
double castMaxInput = (double)maxInput;
if (x < 0 || x > castMaxInput || double.IsNaN(x)) {
return double.NaN;
}
double r = 0;
for (double boundary = 1; boundary<=castMaxInput; boundary++) {
if (x <= boundary) {
r += boundary * (x + 1 - boundary);
return r;
}
else {
r += boundary;
}
}
// we should never get here.
throw new SomeException();
}
The exception that would make the most sense here is something like
TheAuthorOfThisMethodScrewedUpException()
Because that's what is going on if we reach the end of the for loop. Unfortunately, with the method structured as above, the compiler does not appear to be smart enough to figure out that the code after the for loop should never happen. So you can't just have nothing there, or the compiler will complain that "not all code paths return a value". Yes, I could put in return double.NaN after the loop in addition to before it. But that would disguise the source of the problem.
My question is – is there an exception that would be appropriate?
I use the InvalidOperationException class for that. It means that the application has reached a state it should not be in.
throw new InvalidOperationException("Invalid state.");
You can also Debug.Assert that something is true, or simply Debug.Fail when execution reaches a particular point.
Debug.Fail("This should never happen!");
But debugging asserts/fails don't work in release mode, only when the DEBUG conditional is defined. Depends on your requirements whether that's desirable.
As #AlexD correctly points out, there's also the Trace class with its corresponding Assert and Fail methods, that will work at run-time to help isolate and fix problems without disturbing a running system, when the TRACE conditional is defined (is set by default in the Project Properties Build tab).
By the way, to answer the question in the title: you can create your own exceptions if you want.
[Serializable]
public class TheAuthorOfThisMethodScrewedUpException : InvalidOperationException
{
private const string DefaultMessage = "The author of this method screwed up!";
public TheAuthorOfThisMethodScrewedUpException()
: this(DefaultMessage, null)
{ }
public TheAuthorOfThisMethodScrewedUpException(Exception inner)
: base(DefaultMessage, inner)
{ }
public TheAuthorOfThisMethodScrewedUpException(string message)
: this(message, null)
{ }
public TheAuthorOfThisMethodScrewedUpException(string message, Exception inner)
: base(message, inner)
{ }
protected TheAuthorOfThisMethodScrewedUpException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context)
{ }
}
And throw it at people.
throw new TheAuthorOfThisMethodScrewedUpException();
As of .NET 7, the UnreachableException should be used.
Don't throw new Exception(), it causes problems for code trying to catch exceptions. The generic, specific exception that you can use is:
throw new InvalidOperationException("Appplication invariants violated");
This assumes you want the error to happen in production, assuming that an error is better than launching missiles and ending the world. Other developers would rather use a method that assumes the invariant can be ignored in production but not at development time and we don't care if we end the world or not.
It looks easy to create a Custom Exception
public class TheAuthorOfThisMethodScrewedUpException: Exception
{
public EmployeeListNotFoundException()
{
}
public EmployeeListNotFoundException(string message)
: base(message)
{
}
public EmployeeListNotFoundException(string message, Exception inner)
: base(message, inner)
{
}
}
then
throw new TheAuthorOfThisMethodScrewedUpException("I am so sorry, this should never happen call me for more info")
Easy! Use the code snippet!
Exception + TAB +TAB
And it will create a new exception for you. This snippet produces this.
[Serializable]
public class MyException : Exception
{
public MyException() { }
public MyException(string message) : base(message) { }
public MyException(string message, Exception inner) : base(message, inner) { }
protected MyException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
You only need to change the name and.. done! ;)