I am working on C# console application.
Want to impliment "Exception Handling".
Below are the code of ConsoleApp.
static public void Main(string[] args)
{
try
{
for (int i = 0; i < 10; i++)
{
ONE_IndependentProcess(i);
}
TWO_IndependentProcess();
THR_IndependentProcess();
}
catch (System.TimeoutException ex)
{
Console.WriteLine("System.TimeoutException");
}
catch (System.Exception ex)
{
Console.WriteLine("System.Exception");
}
finally
{
Console.WriteLine("End.");
}
}
If an error occurs in TWO_IndependentProcess... application stops, without executing the THR_IndependentProcess
#1. In this case i want THR_IndependentProcess to be execute, and write a Exception Error Information of TWO_IndependentProcess in the Console.
If an error occurs in the ONE_IndependentProcess(3) (in 3rd iteration) application stops, without executing the: remaining iteration(4 to 9), TWO_IndependentProcess & THR_IndependentProcess
#2. In this case also i want the app to execute all, and just write a Exception Error Information of ONE_IndependentProcess(3) in the Console.
Note: I have four Catch block with Detail Exception Information and i want to apply all these four catch block in all three IndependentProcess function.
I would recommend you keep just one copy of your error handling logic and make use of lambda functions to wrap the calls with it:
static private void WithCatch(Action f)
{
try
{
f();
}
catch (System.TimeoutException ex)
{
Console.WriteLine("System.TimeoutException");
}
catch (System.Exception ex)
{
Console.WriteLine("System.Exception");
}
}
static public void Main(string[] args)
{
WithCatch(() => {
for (int i = 0; i < 10; i++)
ONE_IndependentProcess(i);
});
// You could also do this inside the for loop for each one if you want
// to attempt all 10 even if one fails:
//for (int i = 0; i < 10; i++)
// WithCatch(() => {ONE_IndependentProcess(i);});
WithCatch(() => {TWO_IndependentProcess();});
WithCatch(() => {THR_IndependentProcess();});
}
You need to move each independent process into a separate try/catch block.
e.g.
static public void Main(string[] args)
{
try
{
for (int i = 0; i < 10; i++)
{
ONE_IndependentProcess(i);
}
}
catch (System.TimeoutException ex)
{
Console.WriteLine("System.TimeoutException");
}
catch (System.Exception ex)
{
Console.WriteLine("System.Exception");
}
finally
{
Console.WriteLine("End.");
}
try
{
TWO_IndependentProcess();
}
catch (System.TimeoutException ex)
{
Console.WriteLine("System.TimeoutException");
}
catch (System.Exception ex)
{
Console.WriteLine("System.Exception");
}
finally
{
Console.WriteLine("End.");
}
try
{
THR_IndependentProcess();
}
catch (System.TimeoutException ex)
{
Console.WriteLine("System.TimeoutException");
}
catch (System.Exception ex)
{
Console.WriteLine("System.Exception");
}
finally
{
Console.WriteLine("End.");
}
}
You will have to use catch blocks within independent functions/process and deal with the exception within that catch block. This way you can allow program execution to continue without terminating.
try using generic functions to record exceptions - that way you can reuse this function within different catch blocks.
Related
In my API, I have over 25 API controllers, in every controller, using the following code to catch exception, I think it is too many code here, any good suggestion for the structure, thanks.
try
{
*code here*
}
catch (UnauthorizedAccessException ex)
{
}
catch (BadRequestException ex)
{
}
catch (HttpRequestException ex)
{
}
catch (TimeoutRejectedException ex)
{
}
catch (FileNotFoundException ex)
{
}
catch (SqlException ex)
{
}
catch (ValidationException ex)
{
}
catch (Exception ex)
{
}
Any simple way to do that.
IF
you plan to handle each exception separately - your approach is the way to go. I suggest to use this "ugly" code simply because it is more readable. If all your exceptions have common handling (for example logging) - you can use only catch (Exception e) and call your logging methods. This will work for all types of exceptions.
OR
If you decide that some of your exceptions might have common handling - you can go with:
try
{
// do
}
catch (Exception e)
{
if (e is BadRequestException ||
e is HttpRequestException ||
e is TimeoutRejectedException )
{
// Log exception
}
}
OR
A good approach is to use a delegate for exception handling. Since you're going to log exceptions, the delegate will handle this.
Action<Exception> HandleError = (e) => {
// Log exception
};
catch (UnauthorizedAccessException e) { HandleError(e); }
catch (BadRequestException e) { HandleError(e); }
catch (HttpRequestException e) { HandleError(e); }
OR
You can combine the first and the second approach
if (e is BadRequestException ||
e is HttpRequestException ||
e is TimeoutRejectedException )
{
HandleError(e);
}
The best way to explain my question is with the following pseudo-code:
try
{
//Do work
}
catch (SqlException ex)
{
if (ex.Number == -2)
{
debugLogSQLTimeout(ex);
}
else
{
//How to go to 'Exception' handler?
}
}
catch (Exception ex)
{
debugLogGeneralException(ex);
}
Exception ex = null;
try
{
//Do work
}
catch (SqlException sqlEx)
{
ex = sqlEx;
if (ex.Number == -2)
{
//..
}
else
{
//..
}
}
catch (Exception generalEx)
{
ex = generalEx;
}
finally()
{
if (ex != null) debugLogGeneralException(ex);
}
The first catch clause that matches is the only one that can possibly run on the same try block.
The best way I can think of to do what you're attempting is to include casts and conditionals in the more general type:
try
{
//Do work
}
catch (Exception ex)
{
var sqlEx = ex as SqlException;
if (sqlEx != null && sqlEx.Number == -2)
{
debugLogSQLTimeout(ex);
}
else
{
debugLogGeneralException(ex);
}
}
If you find yourself writing this over and over again throughout your data layer, at least take the time to encapsulate it in a method.
I do not believe there is any way to do this as the catch blocks are in different scopes. There's no way to re-throw without exiting the try block and no way to 'call' the final catch block because it's only triggered during an exception.
I would suggest the same as roman m above and just make the same call. Otherwise you have to do something really bad. Like the below crazy code which you should never ever use but i included because it does something like what you want.
In general I think what you are doing is controlling normal flow via exceptions which isn't recommended. If you are trying to track for timeouts, you should probably just handle that another way.
Note that you could do something like the code below with the insanity of a goto statement, but i included it so no one can forget what a bad idea this is. =)
void Main()
{
Madness(new NotImplementedException("1")); //our 'special' case we handle
Madness(new NotImplementedException("2")); //our 'special' case we don't handle
Madness(new Exception("2")); //some other error
}
void Madness(Exception e){
Exception myGlobalError;
try
{
throw e;
}
catch (NotImplementedException ex)
{
if (ex.Message.Equals("1"))
{
Console.WriteLine("handle special error");
}
else
{
myGlobalError = ex;
Console.WriteLine("going to our crazy handler");
goto badidea;
}
}
catch (Exception ex)
{
myGlobalError = ex;
Console.WriteLine("going to our crazy handler");
goto badidea;
}
return;
badidea:
try{
throw myGlobalError;
}
catch (Exception ex)
{
Console.WriteLine("this is crazy!");
}
}
// Define other methods and classes here
I want to throw an exception at next catch, (I attached image)
Anybody know how to do this?
C# 6.0 to the rescue!
try
{
}
catch (Exception ex) when (tried < 5)
{
}
You can't, and trying to do so suggests that you've got too much logic in your catch blocks, or that you should refactor your method to only do one thing. If you can't redesign it, you'll have to nest your try blocks:
try
{
try
{
...
}
catch (Advantage.Data.Provider.AdsException)
{
if (...)
{
throw; // Throws to the *containing* catch block
}
}
}
catch (Exception e)
{
...
}
On the other hand, as of C# 6, there are exception filters so you can check a condition before actually catching the exception:
try
{
...
}
catch (Advantage.Data.Provider.AdsException) when (tries < 5)
{
tries++;
// etc
}
// This will catch any exception which isn't an AdsException *or* if
// if the condition in the filter isn't met.
catch (Exception e)
{
...
}
One possibility is nesting the try/catch clause:
try
{
try
{
/* ... */
}
catch(Advantage.Data.Provider.AdsException ex)
{
/* specific handling */
throw;
}
}
catch(Exception ex)
{
/* common handling */
}
there is also another way - using only your general catch statement and checking the exception type yourself:
try
{
/* ... */
}
catch(Exception ex)
{
if(ex is Advantage.Data.Provider.AdsException)
{
/* specific handling */
}
/* common handling */
}
This answer is inspired by Honza Brestan's answer:
}
catch (Exception e)
{
bool isAdsExc = e is Advantage.Data.Provider.AdsException;
if (isAdsExc)
{
tried++;
System.Threading.Thread.Sleep(1000);
}
if (tried > 5 || !isAdsExc)
{
txn.Rollback();
log.Error(" ...
...
}
}
finally
{
It's ugly to have two try blocks nested inside each other.
If you need to use properties of the AdsException, use an as cast instead of is.
I dont want to catch some exception. Can I do it somehow?
Can I say something like this:
catch (Exception e BUT not CustomExceptionA)
{
}
?
try
{
// Explosive code
}
catch (CustomExceptionA){ throw; }
catch (Exception ex)
{
//classic error handling
}
try
{
}
catch (Exception ex)
{
if (ex is CustomExceptionA)
{
throw;
}
else
{
// handle
}
}
Starting with C# 6, you can use an exception filter:
try
{
// Do work
}
catch (Exception e) when (!(e is CustomExceptionA))
{
// Catch anything but CustomExceptionA
}
You can filter it:
if (e is CustomExceptionA) throw;
And of course you can catch it and rethrow it:
try
{
}
catch (CustomExceptionA) { throw; }
catch (Exception ex) { ... }
First off, it's bad practice to catch Exception unless you log and re-throw it. But if you must, you need to catch your custom exception and re-throw it like so:
try
{
}
catch (CustomExceptionA custome)
{
throw custome;
}
catch (Exception e)
{
// Do something that hopefully re-throw's e
}
After being schooled by #Servy in the comments, I thought of a solution that'll let you do [what I think] you want to do. Let's create a method IgnoreExceptionsFor() that looks like this:
public void PreventExceptionsFor(Action actionToRun())
{
try
{
actionToRun();
}
catch
{}
}
This can then be called like this:
try
{
//lots of other stuff
PreventExceptionsFor(() => MethodThatCausesTheExceptionYouWantToIgnore());
//other stuff
}
catch(Exception e)
{
//do whatever
}
That way, every line except for the one with PreventExceptionsFor() will throw exceptions normally, while the one inside PreventExceptionsFor() will get quietly passed over.
I have a C# Console app that starts in 'static int Main(string[] args)', creates an instance of 'EventRecievedProcessor' class and then calls a method on the instance:
static int Main(string[] args)
{
try
{
EventRecievedProcessor proc = new EventRecievedProcessor
if (!proc.Processs())
{
Console.Write(Type + " processing failed. Please check logs for more information.");
Log.Error("Failed to process s");
return (int)RETURNCODES.INTERNALAPPERROR;
}
}
catch (Exception ex)
{
// This is where the System.NullReferenceException from GetLatestEventInfo is currently being caught
Console.WriteLine("Exception message: " + ex.Message);
Console.WriteLine("Exception stack trace: " + ex.StackTrace);
Log.Fatal("An exception has been thrown. Message: " + ex.Message, ex);
return (int)RETURNCODES.INTERNALAPPERROR;
}
}
The instance of 'EventRecievedProcessor' grabs a collection of records and does a foreach over it. It calls a static method (GetLatestEventInfo) on the 'Event' class for each record in the collection:
public class EventRecievedProcessor
{
public bool Processs()
{
List<Event> events = DAL.GetEvents;
foreach (Event e in events)
{
try
{
EventInfo lastEvent = Eventhistory.GetLatestEventInfo(e);
}
catch (Exception ex)
{
// Log exception and continue processing in foreach loop
// This is where I want to catch the NullReferenceException from GetLatestEventInfo
Log.DebugFormat("Error with eventid " + e.EventID);
Log.Error(ex);
}
}
return true;
}
}
When the follwoing method is called, a System.NullReferenceException is thrown:
public class EventHistory
{
public static EventInfo GetLatestEventInfo(int customerCode, string premiscode)
{
EventInfo info = new EventInfo();
// Do some work here...
// This is where the NullReferenceException is being generated.
return info;
}
}
When the NullReferenceException is thrown here, I would expect the catch block in the foreach loop to catch it, log it, and then return control to the foreach loop to continue processing. Instead, the exception is being caught in the top level 'Main' method, which means the app aborts and the remaining records are not processed.
I'm at loss as to how/why the exception bypasses the first catch block. Any ideas on what I'm doing wrong here?
Adding the stack trace:
System.NullReferenceException: Object reference not set to an instance of an object.
at EventProcessor.EventHistory.GetLatestEventInfo(Event e) in C:\Dev\release6.01.100\Events\EventProcessor\EventProcessor\EventHistory.cs:line 65
at EventProcessor.Processors.EventProcessor.Process() in C:\Dev\release6.01.100\Events\EventProcessor\EventProcessor\Processors\EventProcessor.cs:line 32
at EventProcessor.Program.Main(String[] args) in C:\Dev\release6.01.100\Events\EventProcessor\EventProcessor\Program.cs:line 132
Sorry if I've munched some of the names. This is work code, so I tried to change it up a little to avoid any privacy conflicts.
It doesn't bypass anything. Look closely at your stack trace.
Try using Console.WriteLine(ex.ToString());.
You'll see that the exception is not being thrown from where you thought it was.
This simply isn't the case and here's the proof:
class Program
{
static void Main()
{
// no need of try/catch here as exceptions won't propagate to here
Looper();
}
static void Looper()
{
int processedRecords = 0;
for (int i = 0; i < 10; i++)
{
try
{
Thrower(i);
processedRecords++;
}
catch (NullReferenceException ex)
{ }
}
// prints 5 as expected
Console.WriteLine("processed {0} records", processedRecords);
}
static void Thrower(int i)
{
if (i % 2 == 0)
{
throw new NullReferenceException();
}
}
}