Await without async Task

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
28,048
Reaction score
17,803
Hi guys. Please can you guys advise me on something. I have a login page going for my MVC however this "async Task" is actually messing with the way the controller is operating.

Please help me to refactor this so that I can still run these await methods but without the Controller returning an async task. The Login itself is working and returns a token. However having this function in a task is messing with the way the login page redirects to the Home controller. Please assist :X3:

C#:
public async Task<bool> LoginUserAsync(string url, string userName, string password)
{
    try
    {
        TokenRequest Token;
        HttpClient client = new HttpClient();
        var values = new Dictionary<string, string>
        {
        { "email", "[email protected]" },
        { "password", "Admin123" }
        };
      
        var content = new StringContent(JsonConvert.SerializeObject(values), Encoding.UTF8, "application/json");                                                         
        var response = await client.PostAsync(url, content);

        var responseString = await response.Content.ReadAsStringAsync();

        Token = Newtonsoft.Json.JsonConvert.DeserializeObject<TokenRequest>(responseString);
        client.DefaultRequestHeaders.Add("Authorization", "Bearer " + Token.token);
    }
    catch(Exception ex)
    {
        throw ex;
    }

    return true;
}

This is the method behing PostAsync

C#:
public async Task<T> PostAsync<T>(string methodUrl, object model)
{
    HttpClient client = new HttpClient();

    // Now serialzize the object to json
    string jsonData = JsonConvert.SerializeObject(model);

    // Create a content
    HttpContent content = new StringContent(jsonData);
    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

    // Make a request
    var response = await client.PostAsync(methodUrl, content);
    var responseAsString = await response.Content.ReadAsStringAsync();

    // Deserialize the coming object into a T object
    T obj = JsonConvert.DeserializeObject<T>(responseAsString);

    return obj;
}
 
you cannot - to use `await` you must be in an `async` function.

this shouldn't be a problem, something else is happening here.

every one of my controller methods is async.


I am not really sure what you mean by "login page redirects to the Home controller"

Your POST is not doing a redirect, it is returning an object which will be serialised based on the "Accept" header.

Is your javascript actually doing the redirect?

Maybe you are actually not resolving your promise on the JS side correctly?


edit: BTW, your try/catch there is kind of pointless because what it is doing is what will happen anyway. If an exception happens, it will be thrown.
I also would not create a function that returns only one thing (true) in this case. you might as well just return void.

the fact that this function always returns true makes calling code possibly behaving unexpectedly.

Code:
var isLoggedIn = await LoginAsync();
if (isLoggedIn) {
   Console.WriteLine("success");
} else {
   //this can never actually happen
   Console.WriteLine("failed");
}
 
Last edited:
Sorry I'm literally 8 days into MVC, still trying to figure all this out. When I mean returns to Home controller this is what it does on validation success in the Razor View. What happens is if a login is successful or false the AccountController returns one of two options back to the Login.cshtml.

On a separate test platform it works perfectly until Async Await is added to the login controller then it simply sits on the login page and won't budge.

return Json(new { status = true, message = "Login Successfull!" });

return Json(new { status = true, message = "Invalid Login!" });

JavaScript:
<script>
    function Validate() {
    $.ajax(
    {
        type: "POST",
        url: '@Url.Action("Validate", "Account")',
        data: {
        email: $('#email').val(),
        password: $('#password').val()
        },
        error: function (result) {
        alert("There is a Problem, Try Again!");
        },
        success: function (result) {
        console.log(result);
        if (result.status == true) {
            window.location.href = '@Url.Action("Index", "Home")';
        }
        else {
            alert(result.message);
        }
        }
    });
    }
</script>
 
Sorry I'm literally 8 days into MVC, still trying to figure all this out. When I mean returns to Home controller this is what it does on validation success in the Razor View. What happens is if a login is successful or false the AccountController returns one of two options back to the Login.cshtml.

On a separate test platform it works perfectly until Async Await is added to the login controller then it simply sits on the login page and won't budge.

return Json(new { status = true, message = "Login Successfull!" });

return Json(new { status = true, message = "Invalid Login!" });

JavaScript:
<script>
    function Validate() {
    $.ajax(
    {
        type: "POST",
        url: '@Url.Action("Validate", "Account")',
        data: {
        email: $('#email').val(),
        password: $('#password').val()
        },
        error: function (result) {
        alert("There is a Problem, Try Again!");
        },
        success: function (result) {
        console.log(result);
        if (result.status == true) {
            window.location.href = '@Url.Action("Index", "Home")';
        }
        else {
            alert(result.message);
        }
        }
    });
    }
</script>
In general afaik you should work with promises and they should be handled corrected instead of putting everything into $-dot-it. Which means you'd have a service for the js which does the call but returns a promise, then you need to handle that promise and cater for errors if any. e.g. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
 
Hi guys. Please can you guys advise me on something. I have a login page going for my MVC however this "async Task" is actually messing with the way the controller is operating.

Please help me to refactor this so that I can still run these await methods but without the Controller returning an async task. The Login itself is working and returns a token. However having this function in a task is messing with the way the login page redirects to the Home controller. Please assist :X3:

C#:
public async Task<bool> LoginUserAsync(string url, string userName, string password)
{
    try
    {
        TokenRequest Token;
        HttpClient client = new HttpClient();
        var values = new Dictionary<string, string>
        {
        { "email", "[email protected]" },
        { "password", "Admin123" }
        };
     
        var content = new StringContent(JsonConvert.SerializeObject(values), Encoding.UTF8, "application/json");                                                        
        var response = await client.PostAsync(url, content);

        var responseString = await response.Content.ReadAsStringAsync();

        Token = Newtonsoft.Json.JsonConvert.DeserializeObject<TokenRequest>(responseString);
        client.DefaultRequestHeaders.Add("Authorization", "Bearer " + Token.token);
    }
    catch(Exception ex)
    {
        throw ex;
    }

    return true;
}

This is the method behing PostAsync

C#:
public async Task<T> PostAsync<T>(string methodUrl, object model)
{
    HttpClient client = new HttpClient();

    // Now serialzize the object to json
    string jsonData = JsonConvert.SerializeObject(model);

    // Create a content
    HttpContent content = new StringContent(jsonData);
    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

    // Make a request
    var response = await client.PostAsync(methodUrl, content);
    var responseAsString = await response.Content.ReadAsStringAsync();

    // Deserialize the coming object into a T object
    T obj = JsonConvert.DeserializeObject<T>(responseAsString);

    return obj;
}
Your PostAsync should dispose the http client properly, also you are not checking if the response is actually OK and has content before you attempt to *just* read it. I guess the same for LoginUserAsync...
 
I think you aren't showing some things here.
Async/await is basically SOP on MVC + Web API controllers nowadays.

Is this Framework (why?) or Core? shouldn't matter, but interested none the less.


I would also change your login controller, you are possibly going to get unintended side effects by setting the token on the default header.

  • Make login controller return the token.
  • Include the token in your call to other API's
  • if using .Net core, inject http client into code, this will allow connections to be reused.
 
Sorry I'm literally 8 days into MVC, still trying to figure all this out.
Not bad, took me much longer to end up down this rabbit hole.
ASP.NET MVC and Async are separate concepts, when combined they require special knowledge you only find in the trenches.
When something goes wrong ASP.NET will hang, that's why 'async void' is a sin, the reason being SynchronizationContext which doesn't exist in Core.
 
Also note your syntax seems a bit off.

C#:
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + Token.token);
This does nothing, since you create a new HttpClient each time.

C#:
var response = await client.PostAsync(url, content);
This calls PostAsync of HttpClient, not the second method.

C#:
// Create a content
HttpContent content = new StringContent(jsonData);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
The issue here, if you're using this method is that the encoding(UTF-8) isn't set like in the first method.

JavaScript:
data: {
    email: $('#email').val(),
    password: $('#password').val()
}
I don't think that's valid.
 
If you debug it, and it just hangs at the await PostAsync, it means the call never completes.
Without the await, it just continues executing without waiting for the response from the call to be returned.

You can technically remove the async await by doing the following (I'm a bit rusty with this, but I think it should do...):
var response = client.PostAsync(url, content).Result;

You will however see that it still hangs, because the call never completes. Anyway, it is not best practice, so rather don't. Find the real cause.

Some additional feedback.

C#:
    catch(Exception ex)
    {
        throw ex;
    }

    return true;
}

throw ex; // bad- It clears the stack trace.
throw; // good - it preserves the stack trace.

JavaScript:
        if (result.status == true) {

In Javascript, use triple equality operators. They are faster and type-strict.

"1" == 1 // true
"1" === 1 // false
 
On my way back home travelling from Richards Bay. Thanks a million guys I will sit down with a coffee when I get home and check all this out!
 
Put this back into the new code, remove your new way to do this:
Code:
 // Create a content
    HttpContent content = new StringContent(jsonData);
    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

NOTE!!! THIS IS NOT A SIDE_TRACK ANSWER, THIS IS A TRUE SUGGESTION TO TRY SOLVE THE RAISED ISSUE SPECIFICALLY
 
Last edited:
If you debug it, and it just hangs at the await PostAsync, it means the call never completes.
Without the await, it just continues executing without waiting for the response from the call to be returned.

You can technically remove the async await by doing the following (I'm a bit rusty with this, but I think it should do...):
var response = client.PostAsync(url, content).Result;

You will however see that it still hangs, because the call never completes. Anyway, it is not best practice, so rather don't. Find the real cause.

Some additional feedback.



throw ex; // bad- It clears the stack trace.
throw; // good - it preserves the stack trace.



In Javascript, use triple equality operators. They are faster and type-strict.

"1" == 1 // true
"1" === 1 // false
.Result is a sure way to completely **** yourself down the road with blocking the execution.

If you're doing that then you aren't using async correctly to begin with.
 
Last edited:
excellent tip.
This is easy to overlook, and not something that you necessarily know without being told
How about instead of side-tracking with general code review, rather try to give an anwer to the problem? And by the way, this:
Code:
throw ex; // bad- It clears the stack trace.
throw; // good - it preserves the stack trace.

is not as straightforward as this. I was challenged when I did a throw ex, saying it will throw away the stacktrace, and I proved to them it did not in my case. In my case I had no choice but to throw ex, and it retained the stack trace.
 
You sound like you would be a hoot at parties.

you just dId what you accused me of - added nothing to the conversation or solution. Excellent job :thumbsup:
Focus on the details, I did give a solution, please try again. Stop side-tracking. You see you are so used to side-tracking you fail to see that I`m not. This is a tricky issue so you are forgiven this time. Updated my 1st post to make this clear.
 
Top
Sign up to the MyBroadband newsletter
X