I am generating more than 100 messages per second and sending these messages in separate thread. When connection is down, I want to catch the exception in caller. Since all my messages are sent asynchronous, I am not able to catch the exceptions.
Here is the DispatcherTimer code which calls the dispatcherTimer_Tick method
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 0);
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
try
{
item = "some generated message";
Task.Run(() => SendMessage(item));
}
catch (Exception)
{
}
}
Here is the SendMessage code. I have made change by reading Based on: Async/Await - Best Practices in Asynchronous Programming, BUT it's not working
private async static Task SendMessage(string message)
{
try
{
(MQTT.RunAsync(message.ToString(), topic)).Wait();
}
catch (Exception Ex)
{
// Exceptions are not getting cought here
}
}
Definition of MQTT.RunAsync
public static async Task RunAsync(string message)
{
var mqttClient = factory.CreateMqttClient()
try
{
await mqttClient.ConnectAsync(options);
}
catch (Exception exception)
{
}
}
And
Task<MqttClientConnectResult> ConnectAsync(IMqttClientOptions options)
Updated Question
My RunAsync is first trying to connect and if success then it sends the message. so I can't write return while connection check.
public Task RunAsync(string message, string topicName)
{
this.mqttClient.ConnectAsync(this.options);
mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(this._topicname).WithExactlyOnceQoS().Build());
var applicationMessage = new MqttApplicationMessageBuilder().WithTopic(this._topicname)
.WithPayload(message).WithAtLeastOnceQoS().Build();
if (stopSending == false)
{
return mqttClient.PublishAsync(applicationMessage);
}
return null;
}
Event handlers are an exception where async void is allowed
private async void dispatcherTimer_Tick(object sender, EventArgs e) {
try {
item = "some generated message";
await SendMessage(item);
} catch (Exception ex) {
//...handle exception
}
}
Plus you appear to be consuming the exception any way as it is already being caught further down the stack.
Try to keep the code async all the way through and not mix blocking calls like .Wait() or .Result
private static Task SendMessage(string message) {
return MQTT.RunAsync(message, topic);
}
public static async Task RunAsync(string message, string topicName) {
await this.mqttClient.ConnectAsync(this.options);
var topicFilter = new TopicFilterBuilder().WithTopic(this._topicname)
.WithExactlyOnceQoS().Build();
await mqttClient.SubscribeAsync(topicFilter);
var applicationMessage = new MqttApplicationMessageBuilder().WithTopic(this._topicname)
.WithPayload(message).WithAtLeastOnceQoS().Build();
if (stopSending == false) {
await mqttClient.PublishAsync(applicationMessage);
}
}
Related
I have a class SimpleTask which looks like this:
public class SimpleTask<T>
{
private readonly Action<Exception> _errorAction;
private readonly Func<T> _produce;
private readonly Action<T> _then;
public SimpleTask(Func<T> produce, Action<T> then, Action<Exception> errorAction)
{
_then = then ?? throw new ArgumentNullException(nameof(then));
_errorAction = errorAction ?? throw new ArgumentNullException(nameof(errorAction));
_produce = produce ?? throw new ArgumentNullException(nameof(produce));
}
public void Run()
{
using (var backgroundWorker = new BackgroundWorker())
{
var item = default(T);
backgroundWorker.DoWork += (_, e) => item = _produce();
backgroundWorker.RunWorkerCompleted += (_, e) =>
{
if (e.Error != null)
{
_errorAction(e.Error);
return;
}
_then(item);
};
backgroundWorker.RunWorkerAsync();
}
}
}
I would like to use a Task instead of a BackgroundWorker but I end up with something like this:
public class SimpleTask<T>
{
private readonly Action<Exception> _errorAction;
private readonly Func<T> _produce;
private readonly Action<T> _then;
public SimpleTask(Func<T> produce, Action<T> then, Action<Exception> errorAction)
{
_then = then ?? throw new ArgumentNullException(nameof(then));
_errorAction = errorAction ?? throw new ArgumentNullException(nameof(errorAction));
_produce = produce ?? throw new ArgumentNullException(nameof(produce));
}
public void Run()
{
try
{
var synchronizationContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Run(_produce,CancellationToken.None).ContinueWith(t =>
{
if (t.IsFaulted)
{
_errorAction(t.Exception);
}
else if (t.IsCompleted)
{
_then(t.Result);
}
}, CancellationToken.None,TaskContinuationOptions.ExecuteSynchronously,synchronizationContext);
}
catch (Exception ex)
{
_errorAction(ex);
}
}
}
Which is not the same after all. In my unit tests I have to add:
[SetUp]
public void TestSetUp()
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
I wonder if I should keep using the BackgroundWorker and not pollute my code with task/async structures? What is best practice?
You are reinventing the wheel, because the new async functionality handles most of this for you.
I assume you want to:
Run in a background task a compute bound method that returns a result
Handle any exception thrown by that method
Access the returned value if no exception occurred
Here's an example of how to do this using await.
In this example, the compute-bound method is int computeBoundFunction(). The code assumes you have a Windows Forms form with a button called button1 and a multiline TextBox called textBox1:
async void button1_Click(object sender, EventArgs e)
{
textBox1.AppendText("Starting task\r\n");
try
{
int result = await Task.Run(computeBoundFunction);
// Instead of your "then" action, just call the code here.
// In this example, I'm just appending to a multiline text box.
// This runs on the UI thread.
textBox1.AppendText("Task returned " + result);
}
// Instead of your "errorAction" action, handle exceptions here.
// Note that this runs on the UI thread, so you can update controls safely at this point.
catch (Exception exception)
{
textBox1.AppendText("Exception: " + exception.Message);
}
}
int computeBoundFunction()
{
Thread.Sleep(2000); // Emulate workload.
return 42;
// Comment out the return above and uncomment the line below to test the exception handling:
//throw new InvalidOperationException("Test exception");
}
Note that normally you would never use async void instead of async Task, but this rule is relaxed for event handlers such as button1_Click() in this example.
If await can be used only by async methods, how can I call a task from MainPage()?
My code sample:
public MainPage()
{
InitializeComponent();
label.Text=await Task.Run(TaskTest); //this doesn't work
}
private async Task<string> TaskTest()
{
try
{
using (WebClient client = new WebClient())
{
return await client.DownloadStringTaskAsync("https://www.example.com/return.php");
//also tried w/ no success:
//return client.DownloadStringTaskAsync("https://www.example.com/return.php").Result;
}
}
catch (Exception)
{
throw;
}
}
Avoid async void fire-and-forget methods.
Event handlers however are the only exception to that rule.
Reference Async/Await - Best Practices in Asynchronous Programming
In this case, since you want to await the task then create and event and handler that would facilitate the desired behavior
public MainPage() {
InitializeComponent();
Downloading += OnDownloading; //subscribe to event
Downloading(this, EventArgs.Empty); //raise event to be handled
}
private event EventHandler Downloading = delegate { };
private async void OnDownloading(object sender, EventArgs args) {
//Downloading -= OnDownloading; //unsubscribe (optional)
label.Text = await TaskTest(); //this works
}
private async Task<string> TaskTest() {
try {
using (WebClient client = new WebClient()) {
return await client.DownloadStringTaskAsync("https://www.example.com/return.php");
}
} catch (Exception) {
throw;
}
}
You cannot make the Main() method asynchronous and thus, you can use the await keyword in the body of the Main() function.
A simple workaround that you can implement by editing your current code is making your function TaskTest() return void so you don't have to await it's call.
Example:
public MainPage()
{
InitializeComponent();
TaskTest();
}
private async void TaskTest()
{
try
{
using (WebClient client = new WebClient())
{
label.Text = await client.DownloadStringTaskAsync("https://www.example.com/return.php");
}
}
catch (Exception)
{
throw;
}
}
Edit
In case you have to wait for the return value of an asynchronous call without using await, you could go ahead and use a while to check whether the Task has completed or not.
Task<string> accessTokenTask = Task.Run<string>(() => MethodToGetToken());
// wait until operation is done.
while(!accessTokenTask.IsCompleted)
{
accessTokenTask.Wait():
}
// once the task completes, the runtime will step out of the while loop
// and you can access your Token in the Result
string token = accessTokenTask.Result;
Hope this answers your question.
You probably shouldn't call your Task from MainPage. I started with the Visual Studio blank page and tried to do the same thing. I found an answer suggested to use await Navigation.PushModalAsync(NewPage);, and then call the task there Task.Run(async () => { await method(); }).Wait();. It worked, but not the best way to do it.
This article on CodeProject is great to help beginners to add MVVM to the blank page project. You just need to bind the ViewModel to the MainPage, and then call your Task from the ViewModel instead.
public MainPage()
{
InitializeComponent();
this.BindingContext = new MainPageViewModel(this);
}
I am using DispatcherTimer to process a method at a specified interval of time
dispatcherTimer = new DispatcherTimer()
{
Interval = new TimeSpan(0, 0, 0, 1, 0)
};
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
Here is the dispatcherTimer_Tick method
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
try
{
Task.Run(() => MethodWithParameter(message));
}
catch (Exception ex)
{
}
}
Here I am calling MQTTPublisher which is a DLL reference.
private async static void MethodWithParameter(string message)
{
try
{
await MQTTPublisher.RunAsync(message);
}
catch (Exception Ex)
{
}
}
I am not able to catch the exceptions which are thrown in that DLL. How can I get exception to caller?
Definition of RunAsync - This is in separate dll.
public static async Task RunAsync(string message)
{
var mqttClient = factory.CreateMqttClient();
//This creates MqttFactory and send message to all subscribers
try
{
await mqttClient.ConnectAsync(options);
}
catch (Exception exception)
{
Console.WriteLine("### CONNECTING FAILED ###" + Environment.NewLine + exception);
throw exception;
}
}
And
Task<MqttClientConnectResult> ConnectAsync(IMqttClientOptions options)
This is the downside of using async void. Change your method to return async Task instead :
private async static Task MethodWithParameter(string message)
{
try
{
await MQTTPublisher.RunAsync(message);
}
catch (Exception Ex)
{
}
}
Based on: Async/Await - Best Practices in Asynchronous Programming
Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started.
And:
Figure 2 Exceptions from an Async Void Method Can’t Be Caught with Catch
private async void ThrowExceptionAsync()
{
throw new InvalidOperationException();
}
public void AsyncVoidExceptions_CannotBeCaughtByCatch()
{
try
{
ThrowExceptionAsync();
}
catch (Exception)
{
// The exception is never caught here!
throw;
}
}
i have one form which is doing some long process on form load event,
So i want to show One Gif image "Please Wait" during form load event.
below is code.
private void frmWaitShow()
{
try
{
frmWaitwithstatus objWait = new frmWaitwithstatus();// this form has Gif Image for Processing
objWait.lblStatus.Text = "Processing Request, Please wait...";
objWait.ShowDialog();
}
catch (Exception ex)
{
Logger.SystemException(ex);
Logger.FTSError(" ERROR :" + ex.Message + "frmTest || frmWaitShow");
}
}
Thread oThread;
private void frmTest_Load(object sender, EventArgs e)
{
try
{
oThread = new Thread(new ThreadStart(frmWaitShow));
oThread.Start();
//Functions for Connection with devices
if (LoadDatafromDB() == false) return;
if (ElectTestLoad() == false) return;
if (PowerOnSelfTest() == false) { return; }
InitiControlsElectTest();
SetSystemMode(SystemMode.ElectricalMode);
oThread.Abort();
}
catch (Exception ex)
{
oThread.Abort();
Logger.SystemException(ex);
}
}
after Thread.start() my debugger go one one step in each thread main and one i created but after it go to below line.
frmWaitwithstatus.cs constructor first line
public frmWaitwithstatus()
it stop execute my Thread and execute all function of main thread once Main Thread execution complete after then only it start execute my thread (which is Gif processing image).
Using the async/await pattern will made this an easy task and every form will work on UI thread:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void Form1_Load(object sender, EventArgs e)
{
// async show loading form dialog
var loadingForm = new LoadingForm();
var loadingDialogTask = this.InvokeAsync(loadingForm.ShowDialog);
// async loading data
var data = await LoadDataAsync();
listBox1.DataSource = data;
loadingForm.Close();
await loadingDialogTask;
}
private async Task<ICollection<string>> LoadDataAsync()
{
// fake work load
await Task.Delay(4000).ConfigureAwait(false);
return Enumerable.Range(1,20000).Select(e => e.ToString()).ToList();
}
}
Needed async extension for the controls:
public static class ControlAsyncExtensions
{
public static Task InvokeAsync(this Control control, Action action)
{
var tcs = new TaskCompletionSource<bool>();
control.BeginInvoke(new Action(() =>
{
try
{
action();
tcs.SetResult(true);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
));
return tcs.Task;
}
public static Task<T> InvokeAsync<T>(this Control control, Func<T> action)
{
var tcs = new TaskCompletionSource<T>();
control.BeginInvoke(new Action(() =>
{
try
{
tcs.SetResult(action());
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
));
return tcs.Task;
}
}
I'm using Roslyn's scripting API in my application, code snippet as following:
public class ScriptEngine
{
public static string CodeText;
public static event Action<string[]> CompileErrorEvent;
public static async Task<bool> RunScriptAsync(CancellationToken ct)
{
try
{
var scriptResult = await CSharpScript.RunAsync(CodeText, null, new ScriptHost(), null, ct);
return true;
}
catch (Microsoft.CodeAnalysis.Scripting.CompilationErrorException ex)
{
List<string> result = new List<string>();
foreach (var item in ex.Diagnostics)
{
result.Add(item.ToString());
}
if (result.Count > 0)
{
CompileErrorEvent?.Invoke(result.ToArray());
}
return false;
}
catch (Exception ex)
{
IMCP_Base.Dialog.Show.SimpleError("脚本运行", ex.Message, "修改脚本");
return false;
}
}
.......
}
public static CancellationTokenSource ScriptCTS;
private async void btnScriptRun_ItemClick(object sender, ItemClickEventArgs e)
{
ScriptCTS = new CancellationTokenSource();
if (CheckScriptEditorIsNotNull())
{
Script.ScriptEngine.CodeText = ScriptEditor.GetCode();
bool runSuccess = await Script.ScriptEngine.RunScriptAsync(ScriptCTS.Token);
}
}
private void btnScriptStop_ItemClick(object sender, ItemClickEventArgs e)
{
ScriptCTS?.Cancel();
}
CSharpScript.RunAsync method runs well, but when I click ScriptStop button, ScriptCTS?.Cancel() can't cancel running script.
How can I stop or pause a script running?
If you want cancellation points within your scripts, you can use globals, and pass in the CancelationToken, which you can then check in your scripts for cancellation.