如何使用HttpTaskAsyncHandler

时间:2012-08-09 03:58:30

标签: c# .net asynchronous httptaskasynchandler

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
    }

}

我想创建一个异步处理程序,只想返回一个字符串。我怎样才能使这个工作?是否有使用Async方法和任务的简明参考?

3 个答案:

答案 0 :(得分:8)

几点:

  • 您可以await任意Task,而不仅仅是从async方法返回的内容。
  • async方法将返回的值换行到Task<TResult>;如果没有返回值,则将返回值包装为Task
  • 如果您不需要Task.FromResult方法的开销,可以使用多种便捷方法,例如async
  • 如果您必须使用async,则只需制作方法await。如果您不需要制作方法async,请不要。

您可能会发现我的async/await intro有帮助。

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");
  }
}

答案 1 :(得分:1)

你不应该“返回”任务,编译器会隐式执行它,因为它是一个异步函数:

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

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

这是另一种方式,更接近你想要做的事情:(没有异步/等待)

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

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

async的一般参考是here 基本上将async修饰符添加到方法中,使其隐式返回Task。如果返回int,则会将其转换为Task<int>await反之亦然,将Task<int>变为int

答案 2 :(得分:0)

这是一种真正的异步方法:

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

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

    return readTask;
}

如果使用大文件或慢速驱动器上的文件运行此方法,则执行将在文件读取结束前很久返回调用方。在Stephen Cleary的例子中,只有当结果(&#34; foo&#34;)完成计算时,调用者才能恢复控制。

Dispose必须在ContinueWith中,因为方法执行将在文件读取完成之前返回给调用者,因此无法在ProcessRequest方法中关闭文件。

当然可以开始自己的任务。

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;
}

最好有一个CancellationToken并定期检查是否要求取消以允许取消长时间运行的操作。

编辑1

由于@Stephen Cleary强调了第一个样本,这个结果大致或可能完全相同的CIL:

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

        return s;
    }
}

基本上编译器会将等待textFile.ReadToEndAsync()之后的代码转换为ContinueWith。

每种语法都有它的好处,我的偏好是1-2行(即dispose和log)进入ContinueWith,更复杂的继续使用等待。