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方法和任务的简明参考?
答案 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,更复杂的继续使用等待。