Question

I am trying to consume REST service which returns me the data in JSON format. And I am using simple logic. But code get stuck on the line . I have check this code from emulator as well as from Device. var response = await httpClient.SendAsync(request);

Here is my code

public async Task<string> GetMyData(string urlToCall)
        {    
            using (HttpClient httpClient = new HttpClient())
            {                    
                HttpRequestMessage request = new HttpRequestMessage(System.Net.Http.HttpMethod.Get, urlToCall);
                var response = await httpClient.SendAsync(request);
                var responseString = await response.Content.ReadAsStringAsync();
                return responseString;
            }
        }

and calling is like,

string result = GetMyData(url).Result;

Is I am missing something? I want to get the data synchronously, instead of WebClient I choose HTTPClient for synchronous data call.

Can anyone please suggest me any solution.

EDIT

Thanks @Mike Richards for pointing me in right direction I want to achieve the flow like below,

Call from Main.xaml.cs for aunticateuser() -> calling aunticateuser() methode in Process Class-> once response get from service return control back to Main.xaml.cs -> naviagate to another page i.e. Dashboard.xaml

But in real case its working like, call going to aunticateuser() methode in Process Class and where its send request to service and coming back to Main.xaml.cs but not waiting there to listen the response so how I will decide is this user is valid or not until I get the response?

Code

    private void ApplicationBarDone_Click(object sender, EventArgs e)
            {
                bool isValid = checkForValidation();

                if (isValid)
                {
                    string url = txtUrl.Text.ToString().TrimStart(' ').TrimEnd(' ');
                    string login = txtLogin.Text.ToString().TrimStart(' ').TrimEnd(' ');
                    string clientKey = txtSystemKey.Text.ToString().TrimStart(' ').TrimEnd(' ');
                    string psw = txtPassword.Text.ToString().TrimStart(' ').TrimEnd(' ');

                    RestfulWebServiceUserDAO userDAO = new RestfulWebServiceUserDAO();
                    userDAO.authenticateUser(login, psw, clientKey, url);
                   //navigate to another page  from here ??
                }
            }

In RestfulWebServiceUserDAO class authenticateUser() methode present

public async override void authenticateUser(string login, string password, string clientkey, string systemurl)
        {

            string url = systemurl + "/rest/user?login=" + login + "&password=" + password + "&clientkey=" + clientkey + "&languageId=" + 1;  

            string result = await GetMyData(url);
           //or shall I navigate from here?? this is not allowed :|
        }

GetMyData() methode same in RestfulWebServiceUserDAO class that what I have mark above.

Was it helpful?

Solution

Once you go async, you need to go async all the way to the top. But you need to always return an awaitable (commonly a Task).

Exception made for event handlers and method overrides. But in this case those will be fire-and-forget.

What's hapening in your code is that, although inside your authenticateUser (which, by convention, should be called AuthenticateUserAsync) method you are awaiting for the result of GetMyData (again, GetMyDataAsync), you are not returning any awaitable results to the caller. Becaus aysnc methods return to the caller as soon as they hit the first await statement.

Because of that, when ApplicationBarDone_Click calls userDAO.authenticateUser it imediately returns because it's not awaitable.

If you can't change authenticateUser, you simply can't use async-await. But being Windows Phone, network calls need to be asynchronous and you need to change that. Being so, your AuthenticateUserAsync method (remember the convention?) should look something like this:

public async override Task<string> AuthenticateUserAsync(string login, string password, string clientkey, string systemurl)
{

    string url = systemurl + "/rest/user?login=" + login + "&password=" + password + "&clientkey=" + clientkey + "&languageId=" + 1;  

    return await GetMyDataAsync(url);
}

And your ApplicationBarDone_Click should look something like this:

private async void ApplicationBarDone_Click(object sender, EventArgs e)
{
    bool isValid = checkForValidation();

    if (isValid)
    {
        string url = txtUrl.Text.ToString().TrimStart(' ').TrimEnd(' ');
        string login = txtLogin.Text.ToString().TrimStart(' ').TrimEnd(' ');
        string clientKey = txtSystemKey.Text.ToString().TrimStart(' ').TrimEnd(' ');
        string psw = txtPassword.Text.ToString().TrimStart(' ').TrimEnd(' ');

        RestfulWebServiceUserDAO userDAO = new RestfulWebServiceUserDAO();
        string result = await userDAO.AuthenticateUserAsync(login, psw, clientKey, url);

        // do whatever you need to do after login.
        // just remember that, during the call to userDAO.AuthenticateUserAsync
        // the UI is responsive and the user can click again
    }
}

To learn more about asyn-await programming, read my curation.

OTHER TIPS

Try awaiting GetMyData

string result = await GetMyData(url)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top