Task FromResult vs TaskCompletionSource SetResult

6.9k views Asked by At

What is the difference concerning the functionality and meaning of the

TaskCompletionSource + SetResult vs Task + FromResult

in the SendAsync method?

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
    {
        var response = new HttpResponseMessage(HttpStatusCode.Forbidden) {ReasonPhrase = "HTTPS Required"};
        var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>();
        taskCompletionSource.SetResult(response);
        return taskCompletionSource.Task;
    }
    return base.SendAsync(request, cancellationToken);
}

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    if (!request.RequestUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
    {
        HttpResponseMessage reply = request.CreateErrorResponse(HttpStatusCode.BadRequest, "HTTPS is required for security reason.");
        return Task.FromResult(reply);
    }

    return base.SendAsync(request, cancellationToken);
}
5

There are 5 answers

4
Darrel Miller On BEST ANSWER

Task.FromResult was a new addition in .NET 4.5. It is a helper method that creates a TaskCompletionSource and calls SetResult. If you are using .NET 4 or earlier you will have to use SetResult.

0
noseratio On

I believe Task.FromResult() is more efficient, but you could also do the following, which is more readable, IMO:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
        return new HttpResponseMessage(HttpStatusCode.Forbidden) {ReasonPhrase = "HTTPS Required"};
    return await base.SendAsync(request, cancellationToken);
}

You can still override the base's virtual SendAsync, because async doesn't change the method signature.

0
i3arnon On

If all you want is to return a completed Task<TResult> with a result (or a completed Task without one), simply use Task.FromResult.

Task.FromResult is a simple tool to create a finished task with a result. TaskCompletionSource is a much more robust tool that supports everything. You can set exceptions, return a non-completed task and set it's result later and so forth

P.S: It seems like you're trying to "fake" async methods by returning a finished task. Although that's the best way to do it, make sure "faking" async is really what you want to accomplish.

0
Steven Liekens On

I'm fairly sure that Task.FromResult() does something very similar under the cover.

A better use case scenario for TaskCompletionSource is when you implemented multithreading yourself. In that scenario, you immediately return an awaitable task, whose result is not set until the background thread finishes and calls either TaskCompletionSource.SetResult() or TaskCompletionSource.SetException().

0
reexmonkey On

Task.FromResult is a convenient method to create a Task for a synchronous method. Although a Task represents an asynchronous operation, not all Tasks are actually asynchronous and may just be simple wrappers for synchronous methods.

If you use Task.FromResult, then please include in your documentation that your method is not a 'real' asynchronous method but a syntactic cube of sugar. This shall inform the caller not to expect asynchronous behavior from it.

On the other hand, if you want to manually create an asynchronous function, please use the SetResult or TrySetResult methods of TaskCompletionSource as described here.

Regardless of the version of your .NET framework, always use TaskCompletionSource instead of Task.FromResult to create real asynchronous functions.

Sources:

  1. Task.FromResult
  2. Internal Constructor of Task
  3. TaskCompletionSource.SetResult
  4. TaskCompletionSource.TrySetResult