Gav*_*orn 4 .net c# asynchronous async-await
请考虑以下类,该类负责使用.NET HttpClient与API进行通信.
public class ApiServiceAgent
{
public async Task<string> GetItem()
{
var client = new HttpClient();
var uri = new Uri("http://stackoverflow.com");
var response = await client.GetAsync(uri);
return await response.Content.ReadAsStringAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
虽然简化了,但它代表了我如何编写与HTTP API通信的代码.
现在考虑我希望在我自己的Web API项目中使用这个类.为简单起见,我可以说我有两个额外的类(直接或其他方式)调用此类.
这两个类可能是这样的:
public class Controller : ApiController
{
public async Task<string> Get()
{
var repository = new Repository();
return await repository.GetItem();
}
}
public class Repository
{
public async Task<string> GetItem()
{
var serviceAgent = new ApiServiceAgent();
var apiResponse = await serviceAgent.GetItem();
//For simplicity/brevity my domain object is a lowercase string
return apiResponse.ToLower();
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的两个类中,async/Task方法签名已经完全内在地传播到Controller ...在你看到的async/await主题的大多数示例.NET代码中都很常见.
但是,在大多数异步/等待"最佳实践"文章/视频中,您会看到当前强调async/await应仅用于真正的异步操作.
我认为存储库或控制器都不会做任何真正异步的事情 - 这都是在服务代理中完成的.
我是否应该阻止async/await在我的代码中变得如此多产?
以下是否更能代表"最佳实践"async/await?
public class Controller : ApiController
{
public string Get()
{
var repository = new Repository();
return repository.GetItem();
}
}
public class Repository
{
public string GetItem()
{
var serviceAgent = new ApiServiceAgent();
var apiResponseTask = serviceAgent.GetItem();
var apiResponse = apiResponse.GetAwaiter().GetResult();
return apiResponse.ToLower();
}
}
Run Code Online (Sandbox Code Playgroud)
我离开基地了吗?如果是这样的话,请指出我正确的方向.
我认为这些方法是异步的 - 但仅限于API部分.那种异步只会向上传播.
你的第二个实现Repository.GetItem()是有问题的,IMO:
GetResult()的awaiter完成之前的方法.事实上,在我自己的代码中直接使用awaiter是唯一合理的时间是在我看来你实现自己的awaiter时.(这应该是非常罕见的.)在这种情况下,我认为它将与使用相同Task<T>.Result,但任务执行者可能会在调用之前验证任务已完成(或出现故障).这表明你的方法应该有一个Async后缀,但这并不意味着它们需要是async方法.第二种可能会这样做,但第一种可以简单地写成:
public class Controller : ApiController
{
public Task<string> GetAsync()
{
var repository = new Repository();
return repository.GetItemAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
制作一个方法很少有好处,async只要它有一个await直接用于返回值的方法.
对于你的Repository方法,这await将是有用的,因为你有完成后运行的代码 - 你可以ContinueWith直接使用,但这将更痛苦.所以我将其保留为async/ awaitversion,只需将其重命名为GetItemAsync...并且可能ConfigureAwait(false)用于表示您实际上不需要该方法返回相同的上下文.