23

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);
}
i3arnon
  • 113,022
  • 33
  • 324
  • 344
Pascal
  • 12,265
  • 25
  • 103
  • 195

5 Answers5

41

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.

Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
  • That you mentioned the "new additin in .Net 4.5" made it the solution for me which nobody mentioned. – Pascal Jan 22 '14 at 11:16
  • 11
    `Task.FromResult` doesn't use `TaskCompletionSource`. `Task.FromResult` call _Special internal constructor to create an already-completed task_. [From source code comments](http://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,11a386e7d7cae64a). – Fabio Mar 11 '16 at 04:55
  • @Fabio Thanks for clarifying. I probably saw some shim code from MS that faked the method for backward compat and assumed that's how it worked. – Darrel Miller Mar 13 '16 at 23:18
  • 5
    @Miller Please update your answer to include clarification from Fabio. – reexmonkey Oct 23 '18 at 11:09
6

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.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
4

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().

Steven Liekens
  • 13,266
  • 8
  • 59
  • 85
2

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.

noseratio
  • 59,932
  • 34
  • 208
  • 486
0

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
reexmonkey
  • 2,455
  • 1
  • 14
  • 9