Execute async await task WriteMultipleCoilsAsync issue - c#

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;
}

Related

The type arguments for method MyFunction<T>(Func<T>) cannot be inferred from the usage

I am trying out this piece of code below from:
Is there a way to check if a file is in use?
But, it gives error:
The type arguments for method TimeoutFileAction(Func) cannot be inferred from the usage.
Any idea how to fix this?
TimeoutFileAction(() => { System.IO.File.etc...; return null; } );
Reusable method that times out after 2 seconds
private T TimeoutFileAction<T>(Func<T> func)
{
var started = DateTime.UtcNow;
while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
{
try
{
return func();
}
catch (System.IO.IOException exception)
{
//ignore, or log somewhere if you want to
}
}
return default(T);
}
You MUST have an output other than Type of void.
When you do this: () => { System.IO.File.etc...; return null; } the output type is void and you cannot have that for a Func<T>. If you want a Void Type then use Action.
If you want both void and T, then just write an overflow method. Se Code below:
public static void Main()
{
var today = new DateTime(2021, 10, 25, 5, 40, 0);
Console.WriteLine(today.AddHours(7).AddMinutes(36));
TimeoutFileAction(() => { Test(); });
TimeoutFileAction(Test);
}
private static string Test() => "Test";
private static void TimeoutFileAction(Action func)
{
var started = DateTime.UtcNow;
while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
{
try
{
func();
}
catch (IOException exception)
{
//ignore, or log somewhere if you want to
}
}
}
private static T TimeoutFileAction<T>(Func<T> func)
{
var started = DateTime.UtcNow;
while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
{
try
{
return func();
}
catch (IOException exception)
{
//ignore, or log somewhere if you want to
}
}
return default(T);
}

Retry logic with multiple methods

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);
}

A Method which return a value cannot be passed to exception handler

I'm handling exceptions centrally in a method (ExecuteAction(Action action)). I have a problem when passing action to this method when it returns a value.
In following code I'm getting this error:
Since 'System.Action' returns void, a return keyword must not be followed by an object expression
How to solve this problem?
public decimal CalculateInstalment(decimal amount, int months)
{
this.ExecutAction(() =>
{
var result = amount / months;
return Math.Round(result, 2);
});
}
protected bool ExecutAction(Action action)
{
try
{
action();
return true;
}
catch (NullReferenceException e) { _MessageService.ShowErrorMessage(e); return false; ; }
catch (System.Data.SqlTypes.SqlTypeException e) { _MessageService.ShowErrorMessage(e); return false; }
catch (System.Data.SqlClient.SqlException e) { _MessageService.ShowErrorMessage(e); return false; }
catch (System.Exception e) { _MessageService.ShowErrorMessage(e); return false; };
}
As others have said, Action types do not return a value, but you can refer to outer variables. If you're trying to get the value, consider a setup like this:
public decimal CalculateInstalment(decimal amount, int months)
{
var result = 0.0;
this.ExecutAction(() =>
{
result = Math.Round((amount / months), 2);
});
return result;
}
protected bool ExecutAction(Action action)
{
try
{
action();
return true;
}
catch (NullReferenceException e) { _MessageService.ShowErrorMessage(e); return false; ; }
catch (System.Data.SqlTypes.SqlTypeException e) { _MessageService.ShowErrorMessage(e); return false; }
catch (System.Data.SqlClient.SqlException e) { _MessageService.ShowErrorMessage(e); return false; }
catch (System.Exception e) { _MessageService.ShowErrorMessage(e); return false; };
}
Using bool ExecutAction(Action action) to execute a delegate that returns a value doesn't make much sense - how do you expect to retrieve the value from that delegate?
In addition to your ExecuteAction method, you should use the TryXXX pattern (as seen in the various TryParse methods in the BCL) for delegates that return values:
protected T TryExecutAction<T>(Func<T> func, out bool success)
{
try
{
T temp = func();
success = true;
return temp;
}
catch (NullReferenceException e) { _MessageService.ShowErrorMessage(e); }
catch (System.Data.SqlTypes.SqlTypeException e) { _MessageService.ShowErrorMessage(e); }
catch (System.Data.SqlClient.SqlException e) { _MessageService.ShowErrorMessage(e); }
catch (System.Exception e) { _MessageService.ShowErrorMessage(e); };
success = false;
return default(T);
}
Don't forget to return the value back to the caller:
public decimal CalculateInstalment(decimal amount, int months)
{
bool success;
return this.TryExecutAction(() =>
{
var result = amount / months;
return Math.Round(result, 2);
}, out success);
}
You are Returning a value in
this.ExecutAction(() =>
{
var result = amount / months;
return Math.Round(result, 2);
});
}
Actions don't return values. They always "return void" so to speak.
You need to change to:
protected bool ExecutAction(Func<object> fn)
BTW, this is really "smelly" to me... Here is a sample I guess?
protected T Execute<T>(Func<T> fn) {
try {
return fn();
}
catch (Exception ex) {
// do whatever
// return null and check for it. null checking uuuuuggghhhhh
}
}

How to avoid modified closures with ThreadStart

I'm getting an "Access to modified closure" error in Resharper. Is there a way to pass the task as a parameter to the lambda instead of relying upon a closure?
while (!Quitting && TaskQueue.Any())
{
foreach (var task in TaskQueue.ToArray())
{
if (Quitting || task.Code == TaskCode.Quit)
{
Quitting = true;
return;
}
if (!task.Runnable)
{
continue;
}
var thread = new Thread(() =>
{
try
{
task.Callback();
}
catch (Exception e)
{
if (task.Error != null)
{
task.Error(e);
}
}
});
thread.Start();
}
}
You could use the Thread.Start(object state) method:
while (!Quitting && TaskQueue.Any())
{
foreach (var task in TaskQueue.ToArray())
{
if (Quitting || task.Code == TaskCode.Quit)
{
Quitting = true;
return;
}
if (!task.Runnable)
{
continue;
}
var thread = new Thread(state =>
{
var taskState = (Task)state;
try
{
taskState.Callback();
}
catch (Exception e)
{
if (taskState.Error != null)
{
taskState.Error(e);
}
}
});
thread.Start(task);
}
}
which would have been equivalent to using a separate function:
private void Process(object state)
{
var task = (Task)state;
try
{
task.Callback();
}
catch (Exception e)
{
if (task.Error != null)
{
task.Error(e);
}
}
}
which you would have passed like that:
while (!Quitting && TaskQueue.Any())
{
foreach (var task in TaskQueue.ToArray())
{
if (Quitting || task.Code == TaskCode.Quit)
{
Quitting = true;
return;
}
if (!task.Runnable)
{
continue;
}
new Thread(this.Process).Start(task);
}
}

UnobservedTaskException being throw but it is handled by a TaskScheduler.UnobservedTaskException handler and a continuations OnlyOnFaulted handler [duplicate]

This question already has answers here:
How to handle all unhandled exceptions when using Task Parallel Library?
(3 answers)
Closed 4 years ago.
I'm having problems with TPL programming.
I'm getting UnobservedTaskException while using #h4165f8ghd4f854d6f8h solution on [ http://stackoverflow.com/questions/7883052/a-tasks-exceptions-were-not-observed-either-by-waiting-on-the-task-or-accessi/11830087#11830087 ] to handle exceptions but still getting UnobservedTaskException.
I added the following code before starting tasks too:
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
e.SetObserved();
throw e.Exception;
};
but [ http://stackoverflow.com/questions/10874068/exception-thrown-in-task-thread-not-caught-by-unobservedtaskexception ] telling it won't catch every TPL unhandled exception.
I want propagate exceptions until reach top of stack then deal with it.
Can someone help me????
#Jon Skeet
Hi, I did a smaller repro, thanks for checking
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.tplTestOne();
}
public void tplTestOne()
{
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
e.SetObserved();
throw e.Exception;
};
Task tsk_1 = MyClassHere.createHandledTask(() =>
{
double x = 1;
x = (x + 1) / x;
}, false);
Task tsk_2 = MyClassHere.createHandledTask(() =>
{
double y = 0;
throw new Exception("forced_divisionbyzerodontthrowanymore_test"); // here -> System.Exception was unhandled by user code
}, true);
Task tsk_3 = MyClassHere.createHandledTask(() =>
{
double z = 1;
z = (z + 1) / z;
}, true);
Task tsk_4 = MyClassHere.createHandledTask(() =>
{
double k = 1;
k = (k + 1) / k;
}, true);
Console.ReadLine();
}
}
public static class MyClassHere
{
public static void waitForTsk(Task t)
{
try
{
t.Wait();
}
catch (AggregateException ae)
{
ae.Handle((err) =>
{
throw err;
});
}
}
public static void throwFirstExceptionIfHappens(this Task task)
{
task.ContinueWith(t =>
{
var aggException = t.Exception.Flatten();
foreach (var exception in aggException.InnerExceptions)
{
throw exception; // throw only first, search for solution
}
},
TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations
}
public static Task createHandledTask(Action action)
{
return createHandledTask(action, false);
}
public static Task createHandledTask(Action action, bool attachToParent)
{
Task tsk = null;
if (attachToParent)
{
TaskCreationOptions atp = TaskCreationOptions.AttachedToParent;
tsk = Task.Factory.StartNew(action, atp);
}
else
{
tsk = Task.Factory.StartNew(action);
}
tsk.throwFirstExceptionIfHappens();
return tsk;
}
}
Thanks
The solution was based on How to handle all unhandled exceptions when using Task Parallel Library?
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.tplTestOne();
}
public void tplTestOne()
{
//-------------------------------------------------
MyClassHere.onUnobservedTaskException += (object sender, EventException e) =>
{
Console.WriteLine(e.Exception.Message); //its fired OK
};
TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs e) =>
{
Console.WriteLine(e.Exception.Message); // its not fired, buggy
};
//-------------------------------------------------
CancellationTokenSource source = new CancellationTokenSource();
Task tz = MyClassHere.CreateHandledTask(
new TaskScheduled(0, () => {
if (!source.IsCancellationRequested)
{
Console.WriteLine("A-main-task-started");
}
Thread.Sleep(5000);
if (source.IsCancellationRequested)
{
Console.WriteLine("CancelingMainTask");
}
})
, new TaskScheduled(3000, () => { Console.WriteLine("okTaskCalled"); })
, null //new TaskScheduled(0, () => { Console.WriteLine("cancelTaskCalled"); })
, TaskCreationOptions.AttachedToParent
, source.Token
, new TaskScheduled(2000, () =>
{
if (!source.IsCancellationRequested)
{
Console.WriteLine("B-timeout");
}
})
, new TaskScheduled(1000, () =>
{
if (!source.IsCancellationRequested)
{
Console.WriteLine("C-timeout");
}
source.Cancel();
})
);
if(tz != null)
{
tz.ContinueWith(t => { Console.WriteLine("END"); });
}
Task tsk_1 = MyClassHere.createHandledTask(() =>
{
double x = 1;
x = (x + 1) / x;
}, false);
Task tsk_2 = MyClassHere.createHandledTask(() =>
{
double y = 0;
throw new Exception("forced_divisionbyzerodontthrowanymore_test"); // here -> System.Exception was unhandled by user code
}, true);
Task tsk_3 = MyClassHere.createHandledTask(() =>
{
double z = 1;
z = (z + 1) / z;
}, true);
Task tsk_4 = MyClassHere.createHandledTask(() =>
{
double k = 1;
k = (k + 1) / k;
}, true);
Console.ReadLine();
}
}
public class EventException : EventArgs
{
public Exception Exception;
public Task task;
public EventException(Exception err, Task tsk)
{
Exception = err;
task = tsk;
}
}
public class TaskScheduled
{
public int waitTime;
public Action action;
public DateTime datestamp;
public bool isCalled = false;
public TaskScheduled(int _waitTime, Action _action)
{
this.waitTime = _waitTime;
this.action = _action;
}
}
public static class MyClassHere
{
public delegate void UnobservedTaskException(object sender, EventException e);
public static event UnobservedTaskException onUnobservedTaskException;
//-------------------------------------------------
public static void waitForTsk(Task t)
{
try
{
t.Wait();
}
catch (AggregateException ae)
{
ae.Handle((err) =>
{
throw err;
});
}
}
//-------------------------------------------------
public static void RaiseUnobsrvEvtForEachIfHappens(this Task task)
{
task.ContinueWith(t =>
{
var aggException = t.Exception.Flatten();
foreach (var exception in aggException.InnerExceptions)
{
onUnobservedTaskException(task, new EventException(exception, task));
}
},
TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations
}
//-------------------------------------------------
public static Task CreateHandledTask(Action action)
{
return CreateHandledTask(action, false);
}
public static Task CreateHandledTask(Action action, bool attachToParent)
{
Task tsk = null;
tsk = CreateHandledTask(action, attachToParent, CancellationToken.None);
return tsk;
}
public static Task CreateHandledTask(Action action, bool attachToParent, CancellationToken cancellationToken)
{
Task tsk = null;
TaskCreationOptions atp = TaskCreationOptions.None;
if (attachToParent) { atp = TaskCreationOptions.AttachedToParent; }
tsk = CreateHandledTask(action, atp, cancellationToken);
return tsk;
}
public static Task CreateHandledTask(Action action, TaskCreationOptions tco, CancellationToken cancellationToken)
{
Task tsk = null;
tsk = Task.Factory.StartNew(action, cancellationToken, tco, TaskScheduler.Default);
tsk.RaiseUnobsrvEvtForEachIfHappens();
return tsk;
}
public static Task CreateHandledTask(TaskScheduled mainTask,
TaskScheduled onSuccessTask,
TaskScheduled onCancelationTask,
TaskCreationOptions tco,
CancellationToken cancellationToken,
params TaskScheduled[] timeouts)
{
Task tsk = null;
ManualResetEvent me = new ManualResetEvent(false);
if (timeouts == null || timeouts.Length < 1 || timeouts[0] == null)
{
tsk = CreateHandledTask(mainTask.action, tco, cancellationToken);
me.Set();
}
else
{
bool isCancelation = false;
bool isSuccess = true;
Task NonBlockCtxTask = CreateHandledTask(() =>
{
tsk = CreateHandledTask(mainTask.action, tco, cancellationToken);
me.Set();
int qtdt = timeouts.Count(st => st.action != null);
CountdownEvent cde_pas = new CountdownEvent(3);
CountdownEvent cde_pat = new CountdownEvent(qtdt);
Parallel.ForEach<TaskScheduled>(timeouts, (ts) =>
{
try
{
bool itsOnTime = tsk.Wait(ts.waitTime, cancellationToken);
cde_pat.Signal();
if (!itsOnTime)
{
isSuccess = false;
Task tact = CreateHandledTask(ts.action, TaskCreationOptions.None, cancellationToken);
}
}
catch (OperationCanceledException oce)
{
isSuccess = false;
cde_pat.Signal(cde_pat.CurrentCount);
isCancelation = true;
}
});
try
{
isSuccess &= cde_pat.Wait(System.Threading.Timeout.Infinite, cancellationToken) && !isCancelation;
}
catch (OperationCanceledException oce)
{
isCancelation = true;
isSuccess = false;
}
finally
{
cde_pas.Signal();
}
try
{
if (isCancelation && onCancelationTask != null)
{
Thread.Sleep(onCancelationTask.waitTime);
Task tcn = CreateHandledTask(onCancelationTask.action);
}
}
catch { }
finally {
cde_pas.Signal();
}
try
{
if (isSuccess && onSuccessTask != null)
{
Thread.Sleep(onSuccessTask.waitTime);
Task tcn = CreateHandledTask(onSuccessTask.action);
}
}
catch { }
finally
{
cde_pas.Signal();
}
cde_pas.Wait(System.Threading.Timeout.Infinite);
}, TaskCreationOptions.None, cancellationToken);
}
me.WaitOne();
return tsk;
}
//-------------------------------------------------
}

Categories