How do I handle, invoke exceptions from the add function.
The external function will throw two different exceptions depending on the conditions.
I would like to handle each of these exceptions differently in main.
Thanks for helps.
My example code:
static void Main(string[] args)
{
try
{
add(0, 0);
}
catch(Exception ex)
{
if(Exception 1){
//...
}
if(Exception 2){
//...
}
}
}
public static int add (int a, int b)
{
int result = a + b;
if (result == 0)
{
throw new Exception("Exception 1");
}
if(result > 10)
{
throw new Exception("Exception 2");
}
return result;
}
You have to use the message you assign in the add method, and then check the condition inside the main or another place you want The code with a solution:
static void Main(string[] args)
{
try
{
add(0, 0);
}
catch (Exception ex)
{
Console.WriteLine("catch");
if (ex.Message == "Exception 1")
{
Console.WriteLine("1");
}
if (ex.Message == "Exception 2")
{
Console.WriteLine("2");
}
}
}
public static int add(int a, int b)
{
int result = a + b;
if (result == 0)
{
throw new Exception("Exception 1");
}
if (result > 10)
{
throw new Exception("Exception 2");
}
return result;
}
Related
I could us some help getting the WriteMultipleCoilsAsync task to run. I'm getting the error message Cannot assign void to an implicitly-typed variable on the Task.Run statement. I need to capture the response message from WriteMultipleCoilsAsync.
Here the code:
private async void btnWriteMultipleCoils_Click(object? sender, EventArgs e)
{
string discretes = "true,false,true";
bool[] diarray = Array.ConvertAll(discretes.Split(','), bool.Parse);
var response = await Task.Run(() => master.WriteMultipleCoilsAsync(0, diarray));
await Task.CompletedTask;
}
Here is the WriteMultipleCoilsAsync task:
public Task WriteMultipleCoilsAsync(ushort startAddress, bool[] data)
{
return WriteMultipleCoilsAsync(0, startAddress, data);
}
Here is the WriteMultipleCoilsAsync task:
public Task WriteMultipleCoilsAsync(byte slaveAddress, ushort startAddress, bool[] data)
{
ValidateData("data", data, 1968);
WriteMultipleCoilsRequest request = new WriteMultipleCoilsRequest(slaveAddress, startAddress, new DiscreteCollection(data));
return PerformWriteRequestAsync<WriteMultipleCoilsResponse>(request);
}
Here is the PerformWriteRequestAsync Task:
private Task PerformWriteRequestAsync<T>(IModbusMessage request) where T : IModbusMessage, new()
{
return Task.Factory.StartNew(() => base.Transport.UnicastMessage<T>(request));
}
Here is the UnicastMessage method:
internal virtual T UnicastMessage<T>(IModbusMessage message) where T : IModbusMessage, new()
{
IModbusMessage modbusMessage = null;
int num = 1;
bool flag = false;
do
{
try
{
lock (_syncLock)
{
Write(message);
bool flag2;
do
{
flag2 = false;
modbusMessage = ReadResponse<T>();
SlaveExceptionResponse slaveExceptionResponse = modbusMessage as SlaveExceptionResponse;
if (slaveExceptionResponse != null)
{
flag2 = slaveExceptionResponse.SlaveExceptionCode == 5;
if (!flag2)
{
throw new SlaveException(slaveExceptionResponse);
}
Sleep(WaitToRetryMilliseconds);
}
else if (ShouldRetryResponse(message, modbusMessage))
{
flag2 = true;
}
}
while (flag2);
}
ValidateResponse(message, modbusMessage);
flag = true;
}
catch (SlaveException ex)
{
if (ex.SlaveExceptionCode != 6)
{
throw;
}
if (SlaveBusyUsesRetryCount && num++ > _retries)
{
throw;
}
Sleep(WaitToRetryMilliseconds);
}
catch (Exception ex2)
{
if (ex2 is FormatException || ex2 is NotImplementedException || ex2 is TimeoutException || ex2 is IOException)
{
if (num++ > _retries)
{
throw;
}
continue;
}
throw;
}
}
while (!flag);
return (T)modbusMessage;
}
I am implementing retry logic for WCF services on the client side.
I have multiple operations in WCF service with various input parameters and return types.
I created a wrapper that can make a call to these certain methods that have no return type(void) using Action delegate. Is there any way to call methods that have various input parameters and return type.
Or is there any logic to implement retry functionality on the client side that can handle multiple WCF services.
Class RetryPolicy<T>
{
public T ExecuteAction(Func<T> funcdelegate,int? pretrycount = null,bool? pexponenialbackoff = null)
{
try
{
var T = funcdelegate();
return T;
}
catch(Exception e)
{
if (enableRetryPolicy=="ON" && TransientExceptions.IsTransient(e))
{
int? rcount = pretrycount == null ? retrycount : pretrycount;
bool? exbackoff = pexponenialbackoff == null ? exponentialbackoff : pexponenialbackoff;
int rt = 0;
for (rt = 0; rt < rcount; rt++)
{
if (exponentialbackoff)
{
delayinms = getWaitTimeExp(rt);
}
System.Threading.Thread.Sleep(delayinms);
try
{
var T = funcdelegate();
return T;
}
catch(Exception ex)
{
if (TransientExceptions.IsTransient(ex))
{
int? rcount1 = pretrycount == null ? retrycount : pretrycount;
bool? exbackoff1 = pexponenialbackoff == null ? exponentialbackoff : pexponenialbackoff;
}
else
{
throw;
}
}
}
//throw exception back to caller if exceeded number of retries
if(rt == rcount)
{
throw;
}
}
else
{
throw;
}
}
return default(T);
}
}
I use above method and make a call
public string GetCancelNumber(string property, Guid uid)
{
RetryPolicy<string> rp = new RetryPolicy<string>();
return rp.ExecuteAction(()=>Channel.GetCancelNumber(property, uid, out datasetarray));
}
I keep getting error "cannot use ref or out parameters in anonymous delegate"
Here is an example of a simple Retry method:
bool Retry(int numberOfRetries, Action method)
{
if (numberOfRetries > 0)
{
try
{
method();
return true;
}
catch (Exception e)
{
// Log the exception
LogException(e);
// wait half a second before re-attempting.
// should be configurable, it's hard coded just for the example.
Thread.Sleep(500);
// retry
return Retry(--numberOfRetries, method);
}
}
return false;
}
It will return true if the method succeed at least once, and log any exception until then.
If the method fails on every retry, it will return false.
(Succeed means completed without throwing an exception in this case)
How to use:
Assuming sample Action (void method) and sample Func (a method with a return type)
void action(int param) {/* whatever implementation you want */}
int function(string param) {/* whatever implementation you want */}
Execute a function:
int retries = 3;
int result = 0;
var stringParam = "asdf";
if (!Retry(retries, () => result = function(stringParam)))
{
Console.WriteLine("Failed in all {0} attempts", retries);
}
else
{
Console.WriteLine(result.ToString());
}
Execute an action:
int retries = 7;
int number = 42;
if (!Retry(retries, () => action(number)))
{
Console.WriteLine("Failed in all {0} attempts", retries);
}
else
{
Console.WriteLine("Success");
}
Execute a function with an out parameter (int function(string param, out int num)):
int retries = 3;
int result = 0;
int num = 0;
var stringParam = "asdf";
if (!Retry(retries, () => result = function(stringParam, out num)))
{
Console.WriteLine("Failed in all {0} attempts", retries);
}
else
{
Console.WriteLine("{0} - {1}", result, num);
}
In the following, I need to pass nextDB to the Lambda expression in Retry:
Retry.Do(() =>
{
string nextDB = dbList.Next();
using (DataBaseProxy repo = new DataBaseProxy(nextDB))
{
return repo.DoSomething();
}
});
How do I do that? Here is my Retry class:
public static class Retry
{
public static void Do(
Action action,
int retryCount = 3)
{
Do<object>(() =>
{
action();
return null;
}, retryCount);
}
public static T Do<T>(
Func<T> action,
int retryCount = 3)
{
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
return action();
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
}
I think you want to be using Action<T> here. For example:
public static void Do<T>(
Action<T> action,
T param,
int retryCount = 3)
{
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
action(param);
return;
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
You would call this function like this:
Do(s => {
Console.WriteLine(s);
}, "test", 3);
Based on your comments, it seems that you want to pass in multiple databases and try each one in succession until you find one that works. One simple option would be to remove to retryCount and instead pass in your array.
public static void Do<T>(
Action<T> action,
IEnumerable<T> items)
{
var exceptions = new List<Exception>();
foreach(var item in items)
{
try
{
action(item);
return;
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
And now you call it something like this:
Do(s => {
Console.WriteLine(s);
}, new[] { "db1", "db2", "db3" });
I have written a function that may throw various exceptions..
public class MyClass
{
private void Test(string param)
{
if (param.Length > 10)
throw new ArgumentException();
else if (param.Length > 20)
throw new OverflowException();
else if (string.IsNullOrWhiteSpace(param))
throw new ArgumentException();
else if (param.Length < 1)
throw new FormatException();
}
public void Call(string input)
{
try
{
Test(input);
}
catch (Exception ex)
{
HandleException(ex);
}
}
private void HandleException(Exception ex)
{
//Check if ex is of type ArgumentException
//ToDo..
//Check if ex is of type OverflowException
//ToDo...
//Check if ex is of type ArgumentException
//ToDo..
//Check if ex if of type FormatException
//ToDo..
}
}
Is it possible to have the HandleException(ex) private method so that i can handle all exceptions. Otherwise, I have to write separate exception blocks for each expcetions
private void HandleException(Exception ex)
{
if (ex is ArgumentException)
{
//ToDo..
}
else if (ex is OverflowException)
{
//ToDo..
}
else if (ex is FormatException)
{
//ToDo..
}
}
if the performance of "is vs as" is so important for you you can use this approach
private void HandleException(Exception ex)
{
ArgumentException argEx;
OverflowException ovfEx;
FormatException fmtEx;
if ((argEx = ex as ArgumentException) != null)
{
//ToDo..
}
else if ((ovfEx = ex as OverflowException) != null)
{
//ToDo..
}
else if ((fmtEx = ex as FormatException) != null)
{
//ToDo..
}
}
Sometime you need to run specific code on specific threads, for example winforms. To get the code running on the UI thread you need something like this :
this.BeginInvoke(new MethodInvoker(() =>
{
try
{
//code
}
catch(Exception ex)
{
HandleException(ex);
}
}
SynchornixationContext is another way to do the same thing.
Say that we know that we need to run specific code in the UI thread and we have a given way of handling the exceptions that are thrown on this UI thread(BeginInvoke is not blocking so exceptions will not be transfered). How could we create a method that makes the same thing but simplier like this :
RunOnUIThread(MyMethod);
The RunOnUIThread will contains mor or less the same code as the first example in this code.
Is it possible to create a method like this? And if so How?
You can write some nice extension methods like this
public static class ControlExtension
{
public static IAsyncResult BeginInvokeWithExceptionHandling(this Control control, Action method, Action<Exception> exceptionHandler)
{
if (control == null) throw new ArgumentNullException("control");
if (method == null) throw new ArgumentNullException("method");
if (exceptionHandler == null) throw new ArgumentNullException("exceptionHandler");
return control.BeginInvoke(new MethodInvoker(() =>
{
try
{
method();
}
catch (Exception ex)
{
exceptionHandler(ex);
}
}));
}
public static IAsyncResult BeginInvokeWithExceptionHandling<T>(this Control control, Delegate method, Action<Exception> exceptionHandler, params object[] args)
{
if (control == null) throw new ArgumentNullException("control");
if (method == null) throw new ArgumentNullException("method");
if (exceptionHandler == null) throw new ArgumentNullException("exceptionHandler");
return control.BeginInvoke(new MethodInvoker(() =>
{
try
{
method.DynamicInvoke(args);
}
catch (Exception ex)
{
exceptionHandler(ex);
}
}));
}
}
How to use:
private void HandleException(Exception ex)
{
}
private void MyMethod()
{
}
this.BeginInvokeWithExceptionHandling(MyMethod, HandleException);
Note: Due to Delegate.DynamicInvoke this may be little less performing, you can fix it with strong typed delegate. It is also worth noting that control.BeginInvoke is also internally using Delegate.DynamicInvoke if it can't find what the delegate type is.
public static void InvokeControlAction<t>(t cont, Action<t> action) where t : Control
{
if (cont.InvokeRequired)
{ cont.Invoke(new Action<t, Action<t>>(InvokeControlAction),
new object[] { cont, action }); }
else
{ action(cont); }
}
CodeProject Reference
I ended upp with this based on SriramĀ“s suggestion :
public static void SendToUIThread(Action method, bool UseExceptionHandling = true)
{
if (method == null)
throw new ArgumentNullException("method is missing");
_threadSyncContext.Send(new SendOrPostCallback(delegate(object state)
{
if (UseExceptionHandling)
{
try
{
method();
}
catch (Exception ex)
{
ErrorController.Instance.LogAndDisplayException(ex, true);
}
}
else
method();
}), null);
}
public static void PostOnUIThread(this Control control, Action method, bool UseExceptionHandling = true)
{
if (method == null)
throw new ArgumentNullException("method is missing");
if (control.InvokeRequired)
PostOnUIThread(method, UseExceptionHandling);
else
{
if (UseExceptionHandling)
{
try { method(); }
catch (Exception ex) { ErrorController.Instance.LogAndDisplayException(ex, true); }
}
else
method();
}
}