'Get return value of method from TaskCompletionSource
I have a method RenderReport which generates a PDF file (byte[]). This can sometimes hang indefinitely. It should take no more than 15 seconds to complete when successful. Hence, I'm using a TaskCompletionSource to be able to limit the execution time and throw a TimeoutException if it exceeds the timeout.
However, what I can't determine is: how do you provide the byte[] file returned by RenderReport to the SetResult in the following code? longRunningTask.Wait returns a boolean and not the file so where do you get the file from?
I don't want to use longRunningTask.Result as that can introduce deadlock issues. Here's my code:
public async Task RunLongRunningTaskAsync()
{
Task<byte[]> longRunningTask = Task.Run(() => RenderReport());
TaskCompletionSource<byte[]> tcs = new TaskCompletionSource<byte[]>();
Task toBeAwaited = tcs.Task;
new Thread(() => ThreadBody(longRunningTask, tcs, 15)).Start();
await toBeAwaited;
}
private void ThreadBody(Task<byte[]> longRunningTask, TaskCompletionSource<byte[]> tcs, int seconds)
{
bool completed = longRunningTask.Wait(TimeSpan.FromSeconds(seconds));
if (completed)
// The result is a placeholder. How do you get the return value of the RenderReport()?
tcs.SetResult(new byte[100]);
else
tcs.SetException(new TimeoutException("error!"));
}
private byte[] RenderReport()
{
using (var report = new Microsoft.Reporting.WinForms.LocalReport())
{
// Other logic here...
var file = report.Render("PDF", null, out _, out _, out _, out _, out var warnings);
if (warnings.Any())
{
// Log warnings...
}
return file; // How do I get this file?
}
}
Solution 1:[1]
What works for me is to use ContinueWith:
This shows a first run with a successful retrieval in the specified 2-seconds and then a second run where it times out.
So it's just one approach, but is this helpful at all?
using System;
using System.Threading;
using System.Threading.Tasks;
namespace task_completion
{
class Program
{
static void Main(string[] args)
{
runAsync();
Console.ReadKey();
}
static async void runAsync()
{
// Normal
await longRunningByteGetter(1000, new CancellationTokenSource(2000).Token)
.ContinueWith((Task<byte[]> t)=>
{
switch (t.Status)
{
case TaskStatus.RanToCompletion:
var bytesReturned = t.Result;
Console.WriteLine($"Received {bytesReturned.Length} bytes");
break;
default:
Console.WriteLine(nameof(TimeoutException));
break;
}
});
// TimeOut
await longRunningByteGetter(3000, new CancellationTokenSource(2000).Token)
.ContinueWith((Task<byte[]> t) =>
{
switch (t.Status)
{
case TaskStatus.RanToCompletion:
var bytesReturned = t.Result;
Console.WriteLine($"Received {bytesReturned.Length} bytes");
break;
default:
Console.WriteLine(nameof(TimeoutException));
break;
}
});
}
async static Task<Byte[]> longRunningByteGetter(int delay, CancellationToken token)
{
await Task.Delay(delay, token); // This is a mock of your file retrieval
return new byte[100];
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | IVSoftware |

