Handling Exceptions in while loops - c#

I want to log an error message in my application for a retry to call out the webservice but I only want to disply the error message once outside of the while loop instead of logging the error everytime it retries and fails or should I do a do while loop.
int retryCount = x;
int retryWait = y;
int retry = 0;
while (retry <= retryCount)
{
try
{
//get response
}
catch (InvalidOperationException invalid)
{
message = //display status message
}
catch (Exception exc)
{
//display log message
//retry again
retry++;
}
message = "Mamium tries have been exceeded
Logs.WriteError(message);
return false;
}

Simply reset the message, and check if there is one, so something like:
while (retry <= retryCount)
{
try
{
message = null;
//get response
}
catch (InvalidOperationException invalid)
{
message = invalid.Message; //display status message
}
catch (Exception exc)
{
//display log message
//retry again
message = exc.Message; //display status message
retry++;
}
if (!string.IsNullOrEmpty(message))
{
message = "Mamium tries have been exceeded"
Logs.WriteError(message);
return false;
}
}

You could use your retry and retryCount variables, for sample, and use finally block to increment anyway.
{ // main scope
int retry = 0, retryCount = 3;
string message = null;
while (retry < retryCount)
{
try
{
//get response
}
catch (Exception exc)
{
//any error, since you don't need to give another threatment for other erros, just use Exception
message = exc.Message;
}
finally
{
// increment retry anyway
retry++;
}
}
if (retry >= retryCount)
{
message = "Mamium tries have been exceeded"
Logs.WriteError(message);
return false;
}
return true;
}

Related

why Catch block is executing after return statement in C#

I am trying to use try catch in C# application but I am facing problem suppose first-time internet issue came and then again it tries to sync second-time internet came then after return statement it's going again in catch(CommunicationException comEx) block and return false.
why its happening
int SyncFailCount = 0;
private bool SyncCustomers(long TenantId, DataTable dtCusomers)
{
bool IsSyncSuccess = false;
try
{
SyncQBClient client = new SyncQBClient();
client.SynvCustomer(TenantId, dtCusomers);
SyncFailCount = 0;
IsSyncSuccess = true;
}
catch (CommunicationException comEx) // Mohan: Exception due to Internet issue
{
SyncFailCount = SyncFailCount + 1;
Thread.Sleep(300);
if (SyncFailCount <= 5)
{
SyncCustomers(TenantId, dtCusomers);
}
}
catch (TimeoutException TimeoutEx) // Mohan: Exception due to timeout from web service
{
SyncFailCount = SyncFailCount + 1;
Thread.Sleep(300);
if (SyncFailCount <= 5)
{
SyncCustomers(TenantId, dtCusomers);
}
SyncFailCount = 0;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "CashPundit", MessageBoxButtons.OK, MessageBoxIcon.Error);
SyncFailCount = 0;
}
return IsSyncSuccess;
}
If there is an exception in SyncCustomers() you will call SyncCustomers.
As far as good.
Let's pretend that your second run is good and would return True (at return IsSyncSuccess;)
And here is the problem, you are not catching the return statement in your exception handling - the True is getting lost in the catch block.
Instead of recursively calling the method, may try a while loop to get the synchronization work, no matter if there is an exception or not.
int SyncFailCount = 0;
private bool SyncCustomers(long TenantId, DataTable dtCusomers)
{
bool IsSyncSuccess = false;
// While there is no success do the loop
while (!IsSyncSuccess)
{
try
{
SyncQBClient client = new SyncQBClient();
client.SynvCustomer(TenantId, dtCusomers);
SyncFailCount = 0;
IsSyncSuccess = true;
}
catch (CommunicationException comEx) // Mohan: Exception due to Internet issue
{
SyncFailCount = SyncFailCount + 1;
Thread.Sleep(300);
}
catch (TimeoutException TimeoutEx) // Mohan: Exception due to timeout from web service
{
SyncFailCount = SyncFailCount + 1;
Thread.Sleep(300);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "CashPundit", MessageBoxButtons.OK, MessageBoxIcon.Error);
SyncFailCount = 0;
break;
}
// If there are more than 5 Sync Fails, break the loop and return false
if (SyncFailCount > 5)
{
SyncFailCount = 0;
break;
}
}
return IsSyncSuccess;
}
Trace what is happening when there is one CommunicationException or TimeoutException and the Thread.Sleep "fixes" this:
you are calling SyncCustomers from "outside" and setting the local variable IsSyncSuccess to false
you end up in a catch block and call SyncCustomers again.
this sets a new local variable IsSyncSuccess to false
the method succeeds and returns the true value
now you are back in the original version of your method, inside that catch block
you ignore the returned value, and the value of IsSyncSuccess local to this original invovation of your method is still false. This is the value that you are returning.
So a partial solution would be to not ignore the return value when you recursively call SyncCustomers from within a catch block:
IsSyncSuccess = SyncCustomers(...);
But then you still have a possible infinite recursion that you need to deal with:
When there is a CommunicationException or TimeoutException, you are increasing SyncFailCount, and calling SyncCustomers again - which resets that SyncFailCount back to 0! You are never reaching that limit of 5
I am not too sure which .net framework you are using but 4.0 and above i would recommned using Task method instead of thread This is sample only hope you can use this example
class Program
{
static void Main(string[] args)
{
Task<int> task = new Task<int>(Test);
task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
Console.ReadLine();
}
static int Test()
{
throw new Exception();
}
static void ExceptionHandler(Task<int> task)
{
var exception = task.Exception;
Console.WriteLine(exception);
}
}
add this line at the end of each catch Block
return IsSyncSuccess;

Implement retry mechanism on main thread

How would you implement an unlimited retry mechanism in case internal logics fails
something like this, but here you have only one change
static void Main(string[] args)
{
ILog Log = LogManager.GetLogger(typeof(Program));
try
{
StartWorking(Log);
}
catch (Exception ex)
{
Log.Error("Main exited with error: {0}. Restarting app", ex);
Thread.Sleep(5000);
StartWorking(Log);
}
}
private static void StartWorking(ILog Log)
{
Foo t = new Foo();
t.ReadConfiguration();
t.Login();
t.StartWorking();
}
You could use a while loop:
while (true)
{
try
{
StartWorking(Log);
// No exception was thrown, exit the loop
break;
}
catch (Exception ex)
{
Log.Error("Main exited with error: {0}. Restarting app", ex);
Thread.Sleep(5000);
}
}
Note however that this is very bad practice. You definitely don't want to be doing this. Instead you should have a retry logic that after a number of retries just gives up. For example:
const int maxRetries = 5;
for (var i = 0; i < maxRetries; i++)
{
try
{
StartWorking(Log);
// No exception was thrown, exit the loop
break;
}
catch (Exception ex)
{
Log.Error("Main exited with error: {0}. Restarting app", ex);
Thread.Sleep(5000);
}
if (i == maxRetries - 1)
{
throw new Exception("Sorry, we have reached the maximum number of retries for this operation, just giving up");
}
}

Flurl exception not being caught

I don't understand why but I'm receiving Flurl Exceptions and those are not being caught by the try/catch block. Any ideas on why that's happening?
Here's the code:
try
{
var x = await Utils.Sales.GetUrl()
.PostJsonAsync(new Sale
{
MerchantId = Constants.Sandbox.MerchantId
})
.ReceiveJson<Sale>();
var b = x;
}
catch (FlurlHttpTimeoutException)
{
//LogError("Timed out!"); //todo:
}
catch (FlurlHttpException ex)
{
var x = ex.Message;
//todo:
//if (ex.Call.Response != null)
// LogError("Failed with response code " + call.Response.StatusCode);
//else
// LogError("Totally failed before getting a response! " + ex.Message);
}
catch (Exception ex)
{
var a = ex.Message;
}
Here's the output (the only reason why I know the exception is being thrown):
Maybe this page will help https://msdn.microsoft.com/zh-cn/library/jj619227.aspx
Sorry don't have a english version, you can try google translate it.
It's someting wrong with you catch exception type or await code.
Try this way catch your exception:
```
try
{
await t1;
}
catch (AggregateException ex)
{
var innerEx = ex.InnerExceptions[0];
if (innerEx is NotSupportedException)
{
...
}
else if (innerEx is NotImplementedException)
{
...
}
else
{
...
}
}
```

Android error: Nested signal detected - original signal being reported

This is killing me. I'm new to android/Xamarin. I can't find anything on the web that explains what is going on here.
I'm using xamarin forms for my application. I have a page that synchronizes the device with a web service.
The method simply retrieves 100 records at a time from the web service and updates a sqlite table on the device. I randomly get this error. I'm running 5000 records for my test sample.
Here is the button click:
public async void OnSyncCachedData_Clicked(object sender, EventArgs e)
{
activityIndicatorAll.IsRunning = true;
try
{
actIndSyncItems.IsRunning = true;
SyncAllFinished += SynchAllFinishedProcessing;
await Task.Run(async () => await App.ItemsRepo.LoadCacheDataFromCacheAsync(DbPath).ConfigureAwait(false));
}
catch (BAL.Exceptions.NetworkException nex)
{
await DisplayAlert(Messages.TitleError, nex.Message, Messages.MsgOk);
}
catch (Exception ex)
{
await DisplayAlert(Messages.TitleError, string.Format(Messages.MsgAreYouConnectedParm1, ex.Message), Messages.MsgOk);
}
finally
{
EventHandler handler = SyncAllFinished;
if (handler != null)
{
handler(this, new EventArgs());
}
SyncAllFinished -= SynchAllFinishedProcessing;
}
}
the main worker method:
public async Task<bool> LoadCacheDataFromCacheAsync(string dbPath)
{
WebSvcManagers.ItemsManager itemsWebServiceManager = new WebSvcManagers.ItemsManager();
List<Models.WebServiceItems> consumedRecords = new List<Models.WebServiceItems>() { };
int bufferSize = 100;
Log.Debug(TAG, "LoadCacheDataFromCacheAsync starting");
try
{
{
int lastID = 0;
IEnumerable<Models.WebServiceItems> remoteRecords = await BAL.DataAccessHelper.GetItemsFromGPCacheAsync(App.Login, lastID, bufferSize, itemsWebServiceManager).ConfigureAwait(false);
while (remoteRecords.Count() != 0)
{
foreach (Models.WebServiceItems remoteItem in remoteRecords)
{
// DbActionTypes dbAction = (DbActionTypes)remoteItem.DbAction;
Models.Items itemRecord = new Models.Items() { ItemNumber = remoteItem.ItemNumber.ToUpper().Trim(), Description = remoteItem.Description.Trim() };
Log.Debug(TAG, "Processing {0}", remoteItem.ItemNumber.Trim());
bool success = await AddRecordAsync(itemRecord).ConfigureAwait(false);
if (success)
consumedRecords.Add(remoteItem);
}
lastID = remoteRecords.Max(r => r.RecordID) + 1;
remoteRecords = await BAL.DataAccessHelper.GetItemsFromGPCacheAsync(App.Login, lastID, bufferSize, itemsWebServiceManager).ConfigureAwait(false);
}
}
// await UpdateConsumedRecords(consumedRecords).ConfigureAwait(false);
return true;
}
catch (Exception ex)
{
this.StatusMessage = ex.Message;
Log.Debug(TAG, "Error Catch: {0}", StatusMessage);
return false;
}
finally
{
itemsWebServiceManager = null;
HandleSyncFinished(this, new EventArgs());
SyncAllFinished -= HandleSyncFinished;
}
}
My simple webservice manager:
public static async Task<IEnumerable<Models.WebServiceItems>> GetItemsFromGPCacheAsync(Models.Login login, int offset, int bufferCount, WebSvcManagers.ItemsManager manager)
{
try
{
return await manager.GetCacheRecordsAsync(login, offset, bufferCount).ConfigureAwait(false);
}
catch (Exception)
{
throw;
}
}
And the code for the interaction with the web service:
const int bufferSize = 100;
public async Task<IEnumerable<Models.WebServiceItems>> GetCacheRecordsAsync(Models.Login login, int offSet, int bufferCount)
{
string deviceID = App.ConfigSettings.DeviceID.ToString("D");
try
{
///* Testing start */
//return await DataStore(bufferCount, offSet).ConfigureAwait(false);
///* Testing end */
if (!App.IsConnected)
throw new BAL.Exceptions.NetworkException(Messages.ExceptionNetworkConnection);
string user = login.UserName;
string password = login.Password;
HttpClient client = HttpClientExtensions.CreateHttpClient(user, password);
try
{
List<Models.WebServiceItems> items = new List<Models.WebServiceItems>() { };
int lastID = offSet;
int i = 0;
string uri = string.Format("{0}", string.Format(Messages.WebRequestItemsCacheParms3, deviceID, lastID, Math.Min(bufferCount, bufferSize)));
Log.Debug(TAG, string.Format("Webservice {0}", uri));
string response = await client.GetStringAsync(uri).ConfigureAwait(false);
while (i < bufferCount && response != null && response != "[]")
{
while (response != null && response != "[]")
{
dynamic array = JsonConvert.DeserializeObject(response);
foreach (var item in array)
{
i++;
items.Add(new Models.WebServiceItems()
{
ItemNumber = item["ITEMNMBR"].Value.Trim(),
Description = item["ITEMDESC"].Value.Trim(),
DbAction = (int)(item["DbAction"].Value),
RecordID = (int)(item["DEX_ROW_ID"].Value),
});
lastID = (int)(item["DEX_ROW_ID"].Value);
Log.Debug(TAG, string.Format("Webservice {0}", item["ITEMNMBR"].Value.Trim()));
}
if (i < Math.Min(bufferCount, bufferSize))
{
uri = string.Format("{0}", string.Format(Messages.WebRequestItemsCacheParms3, deviceID, lastID + 1, Math.Min(bufferCount, bufferSize)));
Log.Debug(TAG, string.Format("Webservice {0}", uri));
response = await client.GetStringAsync(uri).ConfigureAwait(false);
}
else
break;
}
}
Log.Debug(TAG, string.Format("Webservice return {0} items", items.Count()));
return items;
}
catch (Exception ex)
{
Log.Debug(TAG, "Error Catch: {0}", ex.Message);
throw ex;
}
}
catch (System.Net.Http.HttpRequestException nex)
{
throw new Exception(string.Format(Messages.ExceptionWebServiceLoginParm1, nex.Message));
}
catch (Exception)
{
throw;
}
}
I've had assistance from a Xamarin instructor and we thought we got it, (because this is random), but it clearly is not swatted. I've been hitting my head up against a wall for over 3 weeks on this. It smells like a memory leak, but I have no idea how to find it with such a generic error message that doesn't appear on web searches.
Somebody out there with some major brains, Please help!
Error:
08-03 12:41:11.281 D/X:ItemsRepositiory(16980): UpdateRecordAsync 65702-40710
08-03 12:41:11.306 D/X:ItemsManager(16980): Webservice DeleteCacheRecordAsync 20497
08-03 12:41:11.406 D/X:ItemsManager(16980): Webservice api/InventoryItems?DeviceID=7c5bb45d-2ea0-45b9-ae50-92f2e25a2983&OffSet=20498&Ma‌​x=100&cached=true
Thread finished: <Thread Pool> #7 08-03 12:41:11.521 E/art (16980): Nested signal detected - original signal being reported The thread 'Unknown' (0x7) has exited with code 0 (0x0).
This might be a problem with the VS Android Emulator. As we have shown in tests, this is not reproducible on the Google Android Emulators, nor on Xamarin Android Player, nor on a physical Android device.

How can I pass on an Exception?

Basically, what I want to do is pass a specific Exception to a more general Exception within the same try block. I've tried the following and it doesn't work:
static bool example(int count = 0)
{
try
{
work();
}
catch (TimeoutException e)
{
if (count < 3)
{
Console.WriteLine("Caught TimeoutException: {0}", e.Message);
return example(count + 1);
}
else
{
throw new Exception(e.Message);
}
}
catch (Exception e)
{
Console.WriteLine("Caught Exception: {0}", e.Message + " rethrown");
return false;
}
return true;
}
static void work()
{
throw new TimeoutException("test");
}
I want the TimeoutException to be only handled a certain amount of times before going to a more generic Exception. This is because the TimeoutException has additional information about the exception on a case by case basis. I do not want to duplicate the code for Exception under the else clause of TimeoutException. The reason I want all exceptions to be handled is that there may be other unknown exceptions that are thrown. The nature of the program requires it to not crash so I must account for any other exceptions and log them. How can I implement this?
You would need to nest this as 2 tries if you want to handle this this way:
static bool example(int count = 0)
{
try
{
try
{
work();
}
catch (TimeoutException e)
{
if (count < 3)
{
Console.WriteLine("Caught TimeoutException: {0}", e.Message);
return example(count + 1);
}
else
{
// Just throw, don't make a new exception
throw; // new Exception(e.Message);
}
}
}
catch (Exception e)
{
Console.WriteLine("Caught Exception: {0}", e.Message + " rethrown");
return false;
}
return true;
}
The "inner try/catch" will only catch TimeoutException, so any other exception will always go to the outer scope. When you rethrow, it'll automatically get caught by the outer scope, as well, which eliminates the need for killing the exception information. (If you throw new Exception, you lose your stack trace data, and other very valuable debugging information.)
Here's my take:
bool example()
{
// Attempt the operation a maximum of three times.
for (int i = 0; i < 3; i++)
{
try
{
work();
return true;
}
catch (Exception e)
{
Console.WriteLine("Caught exception {0}", e.Message);
// Fail immediately if this isn't a TimeoutException.
if (!(e is TimeoutException))
return false;
}
}
return false;
}
EDIT
If you want to actually do something with the TimeoutException, you could change the catch block like so:
catch (Exception e)
{
// As Reed pointed out, you can move this into the if block if you want
// different messages for the two cases.
Console.WriteLine("Caught exception {0}", e.Message);
TimeoutException timeoutException = e as TimeoutException;
if (timeoutException != null)
{
// Do stuff with timeout info...
}
else
{
// Not a timeout error, fail immediately
return false;
}
}

Categories