As you can see above, it does a debugger unhandled exception with nothing catching it at the end.
I have an AppDomain Crash Logger set inside of Program that works for everything outside of the await foreachasync() call.
Is there something im missing?
ForEachAsync:
public static class Extensions
{
public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate {
using (partition) {
while (partition.MoveNext()) {
await body(partition.Current);
}
}
}));
}
}
Example:
//Call this in Program or early on in code
UnhandledExceptionLogger.Initialize();
//Call this, Nothing gets caught in the handler
async public void throwException() {
await Extensions.ForEachAsync(source, 10, combo => {
return Task.Run(() => {
throw new IOException();
}
}
}
//Whereas if I call this, it does
public void throwExceptionSynchronous() {
throw new IOException();
}
static class UnhandledExceptionLogger {
public static void Initialize() {
AppDomain.CurrentDomain.UnhandledException += _CurrentDomain_UnhandledException;
}
static void _CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
if (e.IsTerminating) {
MessageBox.Show("UNHANDLED EXCEPTION CAUGHT!\n" + e.ExceptionObject.ToString());
Environment.Exit(1);
}
}
}
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.
Hello How make method MethodA start new execution only when finished previous execution?
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
MethodB();
MethodC();
}
public static void MethodA ()
{
Console.WriteLine("Start");
Thread.Sleep(200);
Console.WriteLine("Stop");
}
public static void MethodB()
{
Task.Run(() => MethodA());
}
public static void MethodC()
{
Task.Run(() => MethodA());
}
}
In this case I have this result
Hello World
Start
Start
Stop
Stop
But I need something like this
Hello World
Start
Stop
Start
Stop
The simplest way is to create a static locking object and reference that in MethodA:
private static readonly object _methodALockObject = new object();
public static void MethodA()
{
lock(_methodALockObject)
{
Console.WriteLine("Start");
Thread.Sleep(200);
Console.WriteLine("Stop");
}
}
Try to use async and await:
public static void Main()
{
Task.Run(async () =>
{
await MethodB();
await MethodC();
}).GetAwaiter().GetResult();
}
public static void MethodA()
{
Console.WriteLine("Start");
Thread.Sleep(200);
Console.WriteLine("Stop");
}
public async static Task MethodB()
{
await Task.Run(() => MethodA());
}
public async static Task MethodC()
{
await Task.Run(() => MethodA());
}
async and await keywords help to make your asynchronous code to be executed in syncronous order.
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);
}
}
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'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.