Cetrus Cetrus - 1 month ago 7
C# Question

How can I throw an exception back to Windows C# form from Task (.net 4.6)

To all of the ass hat users that put this question on hold (Peter Duniho, karthik, VMAtm, wasthishelpful, Petro Korienev) KISS MY ASS you dickwads

I would like to have the user do some data input on my form... and then validate the data on a separate Task (thread) using a BlockingCollection... ( the reason for the blocking collection is because eventually the data will be coming from n users )

However, when I run the code, and reach an error (the internal processing and error that is produced does not matter ) I throw an exception, expecting the exception to be handled by the try/catch in the windows form... however, it never reaches the form... nor can I rethrow it from the Task.Continue method.

Additionally, the task dies and further processing on the BlockingCollection ceases.

SC s;
private void Form1_Load(object sender, EventArgs e)
{
s = new SC();
}

private void button_ValidateData_Click(object sender, EventArgs e)
{
int x = Convert.ToInt32(textBoxUserData.Text);
try
{
s.AddData(x); // task is dead now... and I didn't catch the exception here
}
catch( Exception e)
{
// inform the user...
MessageBox.Show(e.Message);
}
}


Here is my SC class:

public class SC
{
private BlockingCollection<int> Items;

public SC()
{
Items = new BlockingCollection<int>();

startWaitingForData();
}

public void AddData(int x)
{
Items.Add(x);
}

private void startWaitingForData()
{
// wait for available data
Task t = Task.Factory.StartNew(() => task_DoCollection());

t.ContinueWith(e =>
{
Console.WriteLine(e.Exception.Message);

throw new Exception("Exception was thrown... I can't seem to rethrow to my Form? ");

}, TaskContinuationOptions.OnlyOnFaulted);

t.ContinueWith(e =>
{
Console.WriteLine(e.Status);

}, TaskContinuationOptions.OnlyOnRanToCompletion);
}

private void task_DoCollection()
{
foreach (var x in Items.GetConsumingEnumerable())
{
check(x);
}
}

private void check(int x)
{
// some problem will throw an exception...
throw new Exception("simulated error with exception");
}
}


Please help me understand why the exception is not propagated to the Form and why the task dies.

Answer

I am not really sure what you are trying to do, but the way you did it can't work.

Task creates a separate continuation of code, and the your main thread won't wait for exceptions and catch them.

Non async/await solution

if you want to get the exception in the main thread you will have to call t.Wait() which will block your thread which is probably something you don't really want.

You have two choices in this case - either call an event when the task is finished or an exception is thrown - or you can make your Task t a public property and call t.Wait() in

try
{
    s.AddData(x);  // task is dead now... and I didn't catch the exception here
    s.Task.Wait(); // assuming Task is a public property of SC referencing t
}

Async/await solution

the prefered method, since it won't block the UI is something like this - you should read about async/await and TaskCompletionSource to understand

SC s;
private void Form1_Load(object sender, EventArgs e)
{
   s = new SC();
}

private async void button_ValidateData_Click(object sender, EventArgs e)
{
    int x = Convert.ToInt32(textBoxUserData.Text);
    try
    {
        s.AddData(x);  // task is dead now... and I didn't catch the exception here
        await s.Task; // this will cause the exception to be caught
    }
    catch( Exception e)
    {
        // inform the user...
        MessageBox.Show(e.Message);
    }
}

with SC class:

public class SC
{
    public Task Task => CompletionSource.Task
    private TaskCompletionSource<object> CompletionSource;
    private BlockingCollection<int> Items;

    public SC()
    {
        Items = new BlockingCollection<int>();
        CompletionSource = new TaskCompletionSource
        startWaitingForData();
    }

    public void AddData(int x)
    {
         Items.Add(x);
    }

    private void startWaitingForData()
    {
        // wait for available data
        Task = Task.Factory.StartNew(() => task_DoCollection());

        Task.ContinueWith(e =>
        {
            Console.WriteLine(e.Exception.Message);
            CompletionSource.SetException(e.Exception); // states that an exception was thrown
         }, TaskContinuationOptions.OnlyOnFaulted);

         Task.ContinueWith(e =>
         {
            Console.WriteLine(e.Status);
            CompletionSource.SetResult(null); // task completed successfully
         }, TaskContinuationOptions.OnlyOnRanToCompletion);
    }

    private void task_DoCollection()
    {
        foreach (var x in Items.GetConsumingEnumerable())
        {
            check(x);
        }
    }

    private void check(int x)
    {
        // some problem will throw an exception... 
        throw new Exception("simulated error with exception");
    }
}
Comments