سؤال

public class FooHandler  : HttpTaskAsyncHandler
{
    public override async Task ProcessRequestAsync(HttpContext context)
    {
        return await new AdRequest().ProcessRequest();
        // getting error here. "Return type of async type is void"
    }
}

public class FooRequest
{

    public async Task<String> ProcessRequest()
    {
        //return await "foo"; obviously nothing to wait here
    }

}

I want to make a async handler and just want to return a string. How can i get this working? and is there a concise reference to work with Async methods and Tasks?

هل كانت مفيدة؟

المحلول

A few points:

  • You can await any Task, not just ones returned from async methods.
  • async methods wrap their returned value into a Task<TResult>; if there is no return value, they wrap the return itself into a Task.
  • There are several convenience methods available, e.g., Task.FromResult, if you don't need the overhead of an async method.
  • Only make a method async if you have to use await in it. If you don't need to make the method async, don't.

You may find my async/await intro helpful.

public class FooHandler  : HttpTaskAsyncHandler
{
  public override Task ProcessRequestAsync(HttpContext context)
  {
    return new AdRequest().ProcessRequest();
  }
}

public class AdRequest
{
  public Task<String> ProcessRequest()
  {
    return Task.FromResult("foo");
  }
}

نصائح أخرى

You shouldn't "return" the Task, the compiler will do it implicitly as it is an async function:

public override async Task ProcessRequestAsync(HttpContext context)
{
    await new AdRequest().ProcessRequest();
}

public async Task<String> ProcessRequest()
{
    return "foo";
}

This is another way, closer to what you were trying to do: (without async/await)

public override Task ProcessRequestAsync(HttpContext context)
{
    return new AdRequest().ProcessRequest();
}

public Task<String> ProcessRequest()
{
    return Task.Return("foo");
}

A general reference to async is here Essentially adding the async modifier to a method, makes it return a Task implicitly. If you return an int, it will turn it into a Task<int>. await does the opposite, turning a Task<int> into an int.

This is a truly asynchronous method:

public Task<string> ProcessRequest()
{
    var textFile = File.OpenText("file.txt");
    var readTask = textFile.ReadToEndAsync();

    readTask.ContinueWith(previousTask => textFile.Dispose());

    return readTask;
}

If you run this method with a large file or a file on a slow drive the execution will return to caller long before file reading ends. In Stephen Cleary's example the caller will get back control only when the result ("foo") is finished calculating.

Dispose must be in ContinueWith because the method execution will return to caller before file reading is complete so file can't be closed in ProcessRequest method.

One can of course start their own task.

public Task<string> ProcessRequest(CancellationToken cancellationToken)
{
    var readTask = Task.Run(() =>
    {
        using (var textFile = File.OpenText("file.txt"))
        {
            var text = textFile.ReadToEnd();

            cancellationToken.ThrowIfCancellationRequested();

            var processedText = text.Replace("foo", "bar");

            return processedText;
        }
    });

    return readTask;
}

It is a good practice to have a CancellationToken and periodically check if cancellation was requested to allow long running operarions to be cancelled.

Edit 1

As @Stephen Cleary highlighted the first sample and this result in approximately or maybe exactly the same CIL:

public async Task<string> ProcessRequest()
{
    using (var textFile = File.OpenText("file.txt"))
    {
        var s = await textFile.ReadToEndAsync();

        return s;
    }
}

Basically the compiler will transform the code following await textFile.ReadToEndAsync() into ContinueWith.

Each syntax has its benefits, my preference is that 1-2 lines (i.e. dispose and log) go into ContinueWith, more complex continuation uses await.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top