C# 如何使用HttpTaskAsyncHandler 公共类FooHandler:HttpTaskAsyncHandler { 公共重写异步任务ProcessRequestAsync(HttpContext上下文) { 返回等待新地址().ProcessRequest(); //此处获取错误。“异步类型的返回类型为void” } } 公共类请求 { 公共异步任务ProcessRequest() { //返回等待“foo”;显然这里没有等待的内容 } }

C# 如何使用HttpTaskAsyncHandler 公共类FooHandler:HttpTaskAsyncHandler { 公共重写异步任务ProcessRequestAsync(HttpContext上下文) { 返回等待新地址().ProcessRequest(); //此处获取错误。“异步类型的返回类型为void” } } 公共类请求 { 公共异步任务ProcessRequest() { //返回等待“foo”;显然这里没有等待的内容 } },c#,.net,asynchronous,httptaskasynchandler,C#,.net,Asynchronous,Httptaskasynchandler,我想创建一个异步处理程序,只想返回一个字符串。我怎样才能让它工作?使用异步方法和任务有简明的参考吗?您不应该“返回”任务,编译器会隐式执行它,因为它是一个异步函数: public class FooHandler : HttpTaskAsyncHandler { public override async Task ProcessRequestAsync(HttpContext context) { return await new AdRequest().Pr

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

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

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
    }

}
公共重写异步任务ProcessRequestAsync(HttpContext上下文)
{
等待新的AdRequest().ProcessRequest();
}
公共异步任务ProcessRequest()
{
返回“foo”;
}
这是另一种方式,更接近于您试图做的事情:(没有异步/等待)

公共覆盖任务ProcessRequestAsync(HttpContext上下文)
{
返回新的AdRequest().ProcessRequest();
}
公共任务ProcessRequest()
{
返回任务。返回(“foo”);
}
async
的一般参考是 本质上,将
async
修饰符添加到方法中,使其隐式返回
任务。如果返回int,它将把它转换为
任务
await
的作用正好相反,将
任务
转换为
int

以下几点:

  • 您可以等待任何
    任务,而不仅仅是从
    async
    方法返回的任务
  • async
    方法将其返回值包装到
    任务中
    ;如果没有返回值,它们将返回本身包装到
    任务中
  • 如果不需要
    async
    方法的开销,可以使用几种方便的方法,例如
    Task.FromResult
  • 仅当必须在方法中使用
    wait
    时,才将其设为
    async
    。如果不需要使方法
    异步
    ,请不要这样做
你会发现我的建议很有帮助

公共类FooHandler:HttpTaskAsyncHandler
{
公共覆盖任务ProcessRequestAsync(HttpContext上下文)
{
返回新的AdRequest().ProcessRequest();
}
}
公共类请求
{
公共任务ProcessRequest()
{
返回Task.FromResult(“foo”);
}
}

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

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");
  }
}
public Task ProcessRequest()
{
var textFile=File.OpenText(“File.txt”);
var readTask=textFile.ReadToEndAsync();
readTask.ContinueWith(previousTask=>textFile.Dispose());
返回readTask;
}
如果对大文件或慢速驱动器上的文件运行此方法,则执行将在文件读取结束之前很久返回调用方。在Stephen Cleary的示例中,调用者只有在结果(“foo”)完成计算后才能获得控制权

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

一个人当然可以开始自己的任务

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

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

    return readTask;
}
公共任务处理请求(CancellationToken CancellationToken)
{
var readTask=Task.Run(()=>
{
使用(var textFile=File.OpenText(“File.txt”))
{
var text=textFile.ReadToEnd();
cancellationToken.ThrowIfCancellationRequested();
var processedText=text.Replace(“foo”、“bar”);
返回已处理的文本;
}
});
返回readTask;
}
拥有CancellationToken并定期检查是否请求取消以允许取消长时间运行的操作是一种很好的做法

编辑1

正如@Stephen Cleary突出显示的第一个样本,这导致了大致或可能完全相同的CIL:

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;
}
公共异步任务ProcessRequest()
{
使用(var textFile=File.OpenText(“File.txt”))
{
var s=await textFile.ReadToEndAsync();
返回s;
}
}
基本上,编译器会将wait textFile.ReadToEndAsync()下面的代码转换为ContinueWith


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

Stephen如果我改用TCS:
return new TaskCompletionSource()…
-该方法将只在
setResult
…上退出,对吗?有点错-但我又读了你的文章,当你说“不阻塞线程”时,你没有提到链必须一直到顶端:例如:
public void DoSomethingAsync(){doSomething1();}public async Task doSomething1(){wait Task.Delay(100);}
-这里一个线程将被阻塞(imho),因为顶端方法不是异步的。(再次-imho)。我想说的是,这应该被添加。在你的例子中,没有线程被阻塞。我不确定我是否理解你的问题;你们可以发布一个实际的SO问题吗?这是一个糟糕的例子,因为它实际上并没有使用任务,所以那个些仅仅从web复制代码片段的开发人员实际上会编写阻塞代码。特别值得一提的是,在网络环境中,异步方法中使用的对象不应在执行结束之前被处理。我将在回答中添加一个示例方法。@user3285954:op特别询问如何同步实现异步接口方法(只返回一个字符串)。最干净的方法是
Task.FromResult
。您的第一个示例并不比
使用(var textFile=…){return await textFile.ReadToEndAsync();}
——除了
使用
+
await
方法更清晰之外。第二个例子更危险;一般来说,您应该避免在ASP.NET上运行
Task.Run
public Task<string> ProcessRequest()
{
    var textFile = File.OpenText("file.txt");
    var readTask = textFile.ReadToEndAsync();

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

    return readTask;
}
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;
}
public async Task<string> ProcessRequest()
{
    using (var textFile = File.OpenText("file.txt"))
    {
        var s = await textFile.ReadToEndAsync();

        return s;
    }
}