user5326354
user5326354

Reputation:

Task.Wait always returns false although task finished

I'm using HttpClient trying to execute a POST method in Web API controller. The controller method is synchronous. I'm doing so this way:

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

After that I'm calling Wait:

var result = response.Wait(15000);

When running this code, I see the http finish executing, yet the result value is always false. What can I be missing?

Edit: I now tried an async approach yet it didn't help me as well

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

Test project:

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 }
}

What am I doing wrong? When debugging I see that the controller method returns a good response, yet it never reaches back to my test

Upvotes: 8

Views: 1398

Answers (4)

Gururaj
Gururaj

Reputation: 539

The result may always be false because the _db.AddItem is returning false all the time. If not, I've made a change in your code ideally which should work for you

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 }
}

Since Method2 returns an Async Task, the ContinueWith will not wait for it to complete and hence it may required await on the method invocation.

Upvotes: 0

Larry Dukek
Larry Dukek

Reputation: 2199

I assume your initial code looked something like this...

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

And yes, result will be false after waiting the 15 seconds. This is because you have setup the request, A.K.A response, but you haven't actually made the called and any response.Wait(n) will return false.

You just need to start the ReadAsAsync...

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

However, I think you will find you can skip the response.Wait(n) all together, as it will return true because the ReadAsAsync() will wait to return or fail. If you're looking to configure the request timeout, you can do that in the HttpClient and your ReadAsAsync will throw an AggregateException with an InnerException of TaskCanceledException.

On a side note, you don't need to use owin.HttpClient you can just instantiate a new HttpClient. I believe the owin object you are referring to is for self hosting your WebApi, I don't know if that matters. But let's say you are calling Add(Item item) on your WebApi and that db.AddItem(item) will return and ItemPreview object, your code could look like this:

[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 */

}

Upvotes: 0

Nkosi
Nkosi

Reputation: 247008

You are mixing async and blocking calls (ie .Result, .Wait()) which are leading to a deadlock.

This looks more like it is a blocking issue on the test client side.

You need to make the test async all the way through in this case if you want to await on results from the server.

Convert test method to async

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

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

   //Assert
   Assert.IsNotNull(preview);      
}

And update the methods to not mix async and blocking calls.

Method1 does not need asyn/await if it is not using the task after the call so it can be removed and just have the method return the Task that can be awaited

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

Method2 needs to await the response from Method1 and then get its content.

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

Upvotes: 9

MichaelDotKnox
MichaelDotKnox

Reputation: 1310

It doesn't matter if the controller method is synchronous or not. That is purely a concern on the server code. Since the PostAsJsonAsync method is asynchronous, you need to await it:

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

Which will allow your code to wait for the response from the server.

Upvotes: 0

Related Questions