Task.Wait 始终 returns false 尽管任务已完成

Task.Wait always returns false although task finished

我正在使用 HttpClient 尝试在 Web API 控制器中执行 POST 方法。控制器方法是同步的。我是这样做的:

var response = owin.HttpClient.PostAsJsonAsync(uri, body);

之后我打电话给 Wait:

var result = response.Wait(15000);

当 运行 这段代码时,我看到 http 完成执行,但 result 值始终为 false。我可以缺少什么?

编辑: 我现在尝试了一种异步方法,但它对我也没有帮助

public IHttpActionResult Add(Item item)
{
    var result = _db.AddItem(item);
    return Ok(result);
}

测试项目:

TestServer _owinTestServer;
public async Task<HttpResponse message> Method1(string url, object body)
{
    return await 
   _owinTestServer.HttpClient.PostAsJsonAsync(url,body);
}

public async Task<ItemPreview> Method2(object body);
{
     return await Method1("..", body ).Result.Content.ReadAsAsync<ItemPreview>();
}

[TestMethod]
public void test1()
{
    Item item = new(...);
    Method2(item).Continue with(task => {// Never reach     here }
}

我做错了什么? 调试时我看到控制器方法 returns 一个很好的响应,但它永远不会回到我的测试

控制器方法是否同步并不重要。这纯粹是对服务器代码的关注。由于PostAsJsonAsync方法是异步的,你需要await它:

var response = await owin.HttpClient.PostAsJsonAsync(uri, body);

这将允许您的代码等待服务器的响应。

您正在混合异步和阻塞调用(即 .Result.Wait()),这会导致死锁。

这看起来更像是测试客户端的阻塞问题。

在这种情况下,如果您想等待来自服务器的结果,则需要使测试始终异步。

将测试方法转换为异步

[TestMethod]
public async Task test1() {
   //Arrange
   Item item = new Item(...);

   //Act
   var preview = await Method2(item);

   //Assert
   Assert.IsNotNull(preview);      
}

并更新方法以不混合异步和阻塞调用。

Method1 不需要 asyn/await 如果它在调用后不使用任务,那么它可以被删除,只需要方法 return 和 Task可以期待

TestServer _owinTestServer;
public Task<HttpResponse> Method1(string url, object body) {
    return _owinTestServer.HttpClient.PostAsJsonAsync(url, body);
}

Method2 需要 await 来自 Method1 的响应,然后获取其内容。

public async Task<ItemPreview> Method2(object body) {
    var response = await Method1("..", body );
    return await response.Content.ReadAsAsync<ItemPreview>();
}

我假设您的初始代码看起来像这样...

var response = owin.HttpClient.PostAsJsonAsync(uri, body);
var result = response.Wait(15000);
var itemPreview = response.Result.Content.ReadAsAsync<ItemPreview>();
...

是的,等待 15 秒后结果将为 false。这是因为您已经设置了请求,A.K.A 响应,但您实际上并没有进行调用,任何 response.Wait(n) 都将 return false。

您只需要启动 ReadAsAsync...

var response = owin.HttpClient.PostAsJsonAsync(uri, body);
var itemPreview = response.Result.Content.ReadAsAsync<ItemPreview>();

但是,我认为您会发现您可以一起跳过 response.Wait(n),因为它将 return 为真,因为 ReadAsAsync() 将等待 return 或失败。如果您要配置请求超时,您可以在 HttpClient 中执行此操作,并且您的 ReadAsAsync 将抛出 AggregateException 和 TaskCanceledException 的 InnerException。

附带说明一下,您不需要使用 owin.HttpClient 您只需实例化一个新的 HttpClient 即可。我相信您所指的 owin 对象是用于自托管您的 WebApi,我不知道这是否重要。但是假设您在 WebApi 上调用 Add(Item item) 并且 db.AddItem(item) 将 return 和 ItemPreview 对象,您的代码可能如下所示:

[TestMethod]
public void test1()
{
    Item item = new(...);
    var uri = "..";
    var client = new HttpClient();
    var response = client.PostAsJsonAsync(uri, item);
    var itemPreview = response.Result.Content.ReadAsAsync<ItemPreview>();

    /*  The things to happen once you have item preview */

}

结果可能始终为假,因为 _db.AddItem 一直返回假。如果没有,我已经对您的代码进行了理想的更改,这应该适合您

TestServer _owinTestServer;
public async Task<HttpResponse message> Method1(string url, object body)
{
    return await _owinTestServer.HttpClient.PostAsJsonAsync(url,body);
}

public async Task<ItemPreview> Method2(object body);
{
     return await Method1("..", body ).Result.Content.ReadAsAsync<ItemPreview>();
}

[TestMethod]
public void test1()
{
    Item item = new(...);
    await Method2(item).ContinueWith(task => {// Never reach     here }
}

由于方法 2 returns 是一个异步任务,ContinueWith 不会等待它完成,因此在方法调用时可能需要 await