从数据库中获取数据后,我将其序列化为XML。Web Api 2返回数据而不格式化异步
然后,我将该XML作为字符串写入Redis缓存实例。
我希望端点检查数据是否存在于缓存中,并根据结果从缓存中返回数据,或者击中数据库,缓存数据然后返回该数据。如果一切顺利的香蕉试图使它异步时
工作同步码
[HttpGet]
public IHttpActionResult Test(int userId)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
var data = Cache.StringGet("Cart:" + userId);
if (string.IsNullOrEmpty(data))
{
// Grab data from DB and format as XML
Cache.StringSet("Cart:" + userId, data, TimeSpan.FromHours(2));
}
response.Content = new StringContent(data);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
return new ResponseMessageResult(response);
}
:当同步执行
我的代码工作就好了。
破碎异步代码 (我包括必要的代码量最小重现该问题)
[HttpGet]
public async Task<HttpResponseMessage> TestAsync(int userId)
{
var data = await Cache.StringGetAsync("Cart:" + userId);
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent("<test>Test</test>");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
return response;
}
注意,在这个上面的例子我还没有访问异步加载数据。如果我将等待线注释掉,事情就会重新开始。它只有在代码中有await时才会失败。
发生的问题是,50%的时间,请求端点只是...失速,永远不会完成。附上的Fiddler屏幕截图突出了这个问题。
最后,如果跳过媒体格式和内容协商一个更简单的方法,我会很乐意改变我的做法了。
我应该补充说,将使用此端点的服务仅支持XML,并且对每个请求进行反序列化和重新串行化都没有意义。
你有没有试过'等待Cache.StringGetAsync(“Cart:”+ userId).ConfigureAwait(false)'而不是?这听起来像你可能正在经历一个典型的ASP.Net死锁问题(它的组织方式,它喜欢与异步/等待死锁)。 – 2014-11-06 03:40:44
在破损的代码中,你为什么要访问Cache.StringGetAsync,当你在调用Cache.StringGet的工作代码中时,不是已经是Async的TestAsync调用,现在它将等待调用Cache.StringGet的结果。你会检查这是否解决了问题 – 2014-11-06 04:12:35
@MrinalKamboj我的印象是,正确的异步/等待设计是为了使链中的每个方法都是异步的,以避免阻塞错误。例如。异步控制器调用异步服务调用异步数据库存储库,它使用检索数据的异步方法。删除await可以解决问题,但也可以使控制器在HttpContext线程上运行时同步。 Cache.StringGetAsync是对redis实例的远程调用,如果可能的话应该是异步的。 – Bio2hazard 2014-11-06 04:31:15