Reading the response from HttpClient.GetStringAsync - c#

I am working on a Windows Universal app using the new runtime for Windows Phone/Store apps. I am sending a request to a server using the following code and expecting a HTML response back. However when I return the string and display it in the UI, it just says:
"System.Threading.Tasks.Task'1[System.String]"
It's not showing me the actual HTML/XML that should be returned. When I use the same URL in a normal Windows Forms app, it's returning the data I expect but the code I use there is different due to it being Win32 not WinRT/this new RT.
Here's my code. I suspect I am not returning the data in the right format or something but I don't know what I should be doing.
var url = new Uri("http://www.thewebsitehere.com/callingstuff/calltotheserveretc");
var httpClient = new HttpClient();
try
{
var result = await httpClient.GetStringAsync(url);
string checkResult = result.ToString();
httpClient.Dispose();
return checkResult;
}
catch (Exception ex)
{
string checkResult = "Error " + ex.ToString();
httpClient.Dispose();
return checkResult;
}

I don't think the problem is in this code snippet but in the caller. I suspect this code is in a method returning a Task (correct so that the caller can wait for this method's HttpClient call to work) but that the caller isn't awaiting it.
The code snippet looks correct and essentially the same as in the docs at https://msdn.microsoft.com/en-us/library/windows/apps/windows.web.http.httpclient.aspx . GetStringAsync returns a Task. The await will handle the Task part and will return a string into var result. If you break inside the function and examine result or checkResult they'll be the desired strings.
The same thing needs to happen with the caller. If this is in a function
Task<string> GetData()
{
// your code snippet from the post
return checkResult; // string return is mapped into the Task<string>
}
Then it needs to be called with await to get the string rather than the task and to wait for GetData's internal await to finish:
var v = GetData(); // wrong <= var will be type Task<string>
var data = await GetData(); // right <= var will be type string
The only time you wouldn't await the Task is if you need to manipulate the Task itself and not just get the result.

The 'await' operator can only be used within an async method. Change its return type to Task<string> should resolve the problem. The try block should be something like this:
try
{
Task<string> t = httpClient.GetStringAsync(url);
string checkResult = t.Result;
httpClient.Dispose();
return checkResult;
}

Related

call HttpClient GetAsync but app freezes seconds and works as sync mode

Below is my code to get an HTML page
public static async Task<string> GetUrltoHtml(string url)
{
string s;
using (var client = new HttpClient())
{
var result = client.GetAsync(url).Result;
//Console.WriteLine("!!!"+result.StatusCode);
s = result.Content.ReadAsStringAsync().Result; //break point
}
return s;
}
the line
var result = client.GetAsync(url).Result;
causes app freeze seconds and work as sync mode
Your comment welcome
According to the docs
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
So getting Result is a blocking action. You should use await instead.
s = await result.Content.ReadAsStringAsync();
(Result is helpful when the result is ready and you just want to get it. Or in some cases you want to block the thread (but it's not recommended).)

How can I read return value from Async method in C#?

My async method is as below:
public async Task<List<object>> handleSummaryOfWallets()
{
string token = giveMeToken("URL AND CREDS");
Channel channel = new Channel("NANANANA GIROUD", ChannelCredentials.Insecure);
OMGadminAPI.OMGadminAPIClient client = new OMGadminAPI.OMGadminAPIClient(channel);
var summaryBalancesParams = new OMGadminAPIGetCurrenciesSummariesParams();
summaryBalancesParams.AdminAuthTokenSecret = token;
List<object> summariesCurrenciesOMGadmin = new List<object>();
using (var call = client.GetCurrenciesSummaries(summaryBalancesParams))
{
while (await call.ResponseStream.MoveNext())
{
OMGadminAPICurrencySummary currencySummary = call.ResponseStream.Current;
summariesCurrenciesOMGadmin.Add(currencySummary);
Console.WriteLine(summariesCurrenciesOMGadmin);
}
return summariesCurrenciesOMGadmin;
}
}
As you can see, above async method returns list of objects. I call this method as below:
var listOfBalances = balances.handleSummaryOfWallets().Wait();
and it gives me error:
Error CS0815: Cannot assign void to an implicitly-typed variable
From the error, I understand that this is not correct way to call async method. But I need to read ready list of objects from async fetched data. Its request-response, no real stable stream. So I need to generate this list only once per request. I'm using gRPC framework for RPC calls.
Please help me fetch this data and make ready to use.
The Task.Wait method waits for the Task to complete execution. It returns void. That is the reason why the exception.
Now to overcome the exception and to read the return value, one way is as mentioned in other answer and the comments; await the call as below:
public async void TestAsync()
{
var listOfBalances = await handleSummaryOfWallets();
}
Note that your calling method should also be async method now.
As you are calling Wait in your code, it looks that you want the result immediately; you have nothing else left to do that does not depend on result. In that case, you may choose to stop async chain by calling Wait. But you need to do some changes as below:
public void TestAsync()
{
var task = handleSummaryOfWallets();//Just call the method which will return the Task<List<object>>.
task.Wait();//Call Wait on the task. This will hold the execution until complete execution is done.
var listOfBalances = task.Result;//Task is executed completely. Read the result.
}
Note that calling method is no longer async. Other explanation is given in code-comments.
Other short alternative to above code is as below:
public void TestAsync()
{
var listOfBalances = handleSummaryOfWallets().Result;
}
Just use await while calling your method
var listOfBalances = await balances.handleSummaryOfWallets();

Recursive Async/Await API call

I have an async method that makes an API call to a vendor. The vendor has requested that in the event of an error, we make an additional 2 calls with exactly the same information in the calls. My first thought for this scenario is to make my API method recursive. However, after looking at many questions on this site and other articles, I'm having a hard time grasping how async/await works with recursion.
My method (simplified for demonstration) follows. I'm not sure if I should be awaiting the recurisve call? Visual Studio throws the standard Because this call is not awaited, execution will continue...etc if I don't await the recursive call. It does appear to work when I do await the recursive call, I'm just afraid of what I'm doing to stack if I've done this incorrectly. Any help would be appreciated.
public async Task<string> GetData(int UserID, int Retry = 0)
{
try
{
var Request = new HttpRequestMessage(HttpMethod.Post, "myurlhere");
//Set other request info like headers and payload
var Response = await WebClient.SendAsync(Request);
return await Response.Content.ReadAsStringAsync();
}
catch (Exception Ex)
{
if (Retry <= 2)
{
Retry++;
return await GetData(UserID, Retry); //Should I await this?
}
else
{
return "";
}
}
}
It does appear to work when I do await the recursive call,
Grand, so.
I'm just afraid of what I'm doing to stack if I've done this incorrectly.
Because awaiting Tasks that don't return synchronously is handled by a state machine, it is in fact less burden on the stack in such a case than if it was "normal" non-async code. The recursive call becomes another state machine and a reference to it is a field in the first state machine.
It's possible to take an iterative rather than recursive approach to this generally (have a loop and exit on first success) but really since even the non-async equivalent wouldn't have significant stack pressure there's no need to do things any differently than you have done.
This is not a situation where recursion is needed. As others have suggested I would use something like this:
public async Task<string> GetDataWithRetry(int UserID, int Tries = 1)
{
Exception lastexception = null;
for (int trycount=0; trycount < tries; trycount++)
try
{
return await GetData(UserID);
}
catch (Exception Ex)
{
lastexception = Ex;
}
throw lastexception;
}
public async Task<string> GetData(int UserID)
{
var Request = new HttpRequestMessage(HttpMethod.Post, "myurlhere");
//Set other request info like headers and payload
var Response = await WebClient.SendAsync(Request);
return await Response.Content.ReadAsStringAsync();
}

Calling Async in a Sync method

I've been reading examples for a long time now, but unfortunately I've been unable to apply the solutions to the code I'm working with. Some quick Facts/Assorted Info:
1) I'm new to C#
2) The code posted below is modified from Amazon Web Services (mostly stock)
3) Purpose of code is to compare server info to offline already downloaded info and create a list of need to download files. This snip is for the list made from the server side, only option with AWS is to call async, but I need this to finish before moving forward.
public void InitiateSearch()
{
UnityInitializer.AttachToGameObject(this.gameObject);
//these are the access key and secret access key for credentials
BasicAWSCredentials credentials = new BasicAWSCredentials("secret key", "very secret key");
AmazonS3Config S3Config = new AmazonS3Config()
{
ServiceURL = ("url"),
RegionEndpoint = RegionEndpoint.blahblah
};
//Setting the client to be used in the call below
AmazonS3Client Client = new AmazonS3Client(credentials, S3Config);
var request = new ListObjectsRequest()
{
BucketName = "thebucket"
};
Client.ListObjectsAsync(request, (responseObject) =>
{
if (responseObject.Exception == null)
{
responseObject.Response.S3Objects.ForEach((o) =>
{
int StartCut = o.Key.IndexOf(SearchType) - 11;
if (SearchType == o.Key.Substring(o.Key.IndexOf(SearchType), SearchType.Length))
{
if (ZipCode == o.Key.Substring(StartCut + 12 + SearchType.Length, 5))
{
AWSFileList.Add(o.Key + ", " + o.LastModified);
}
}
}
);
}
else
{
Debug.Log(responseObject.Exception);
}
});
}
I have no idea how to apply await to the Client.ListObjectsAsync line, I'm hoping you all can give me some guidance and let me keep my hair for a few more years.
You can either mark your method async and await it, or you can call .Wait() or .Result() on the Task you're given back.
I have no idea how to apply await to the Client.ListObjectsAsync line
You probably just put await in front of it:
await Client.ListObjectsAsync(request, (responseObject) => ...
As soon as you do this, Visual Studio will give you an error. Take a good look at the error message, because it tells you exactly what to do next (mark InitiateSearch with async and change its return type to Task):
public async Task InitiateSearchAsync()
(it's also a good idea to add an Async suffix to follow the common pattern).
Next, you'd add an await everywhere that InitiateSearchAsync is called, and so on.
I'm assuming Client.ListObjectsAsync returns a Task object, so a solution for your specific problem would be this:
public async void InitiateSearch()
{
//code
var collection = await Client.ListObjectsAsync(request, (responseObject) =>
{
//code
});
foreach (var item in collection)
{
//do stuff with item
}
}
the variable result will now be filled with the objects. You may want to set the return type of InitiateSearch() to Task, so you can await it too.
await InitiateSearch(); //like this
If this method is an event handler of some sort (like called by the click of a button), then you can keep using void as return type.
A simple introduction from an unpublished part of the documentation for async-await:
Three things are needed to use async-await:
The Task object: This object is returned by a method which is executed asynchronous. It allows you to control the execution of the method.
The await keyword: "Awaits" a Task. Put this keyword before the Task to asynchronously wait for it to finish
The async keyword: All methods which use the await keyword have to be marked as async
A small example which demonstrates the usage of this keywords
public async Task DoStuffAsync()
{
var result = await DownloadFromWebpageAsync(); //calls method and waits till execution finished
var task = WriteTextAsync(#"temp.txt", result); //starts saving the string to a file, continues execution right await
Debug.Write("this is executed parallel with WriteTextAsync!"); //executed parallel with WriteTextAsync!
await task; //wait for WriteTextAsync to finish execution
}
private async Task<string> DownloadFromWebpageAsync()
{
using (var client = new WebClient())
{
return await client.DownloadStringTaskAsync(new Uri("http://stackoverflow.com"));
}
}
private async Task WriteTextAsync(string filePath, string text)
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath, FileMode.Append))
{
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
}
}
Some thing to note:
You can specify a return value from an asynchronous operations with Task. The await keyword waits till the execution of the method finishes, and returns the string.
the Task object contains the status of the execution of the method, it can be used as any other variable.
if an exception is thrown (for example by the WebClient) it bubbles up at the first time the await keyword is used (in this example at the line string result (...))
It is recommended to name methods which return the Task object as MethodNameAsync
For more information about this take a look at http://blog.stephencleary.com/2012/02/async-and-await.html.

Async WebRequest freezes application

I am building an app that will have registration option and I've made a method for checking whether username is available or not that is async. Method connects via WebRequest to my PHP/MySQL API and retrieves if username is taken or not.
However whenever I try to run this the code blocks on line
var response = await webRequest.GetResponseAsync();
and whole application just freezes. Doing this same method synchronously works fine though.
Whole method:
async public Task<UsernameAvailable> usernameAvailable()
{
try
{
token = "token=single";
function = "&function=checkUser";
string param = "&param=" + User.username;
string result = "";
var webRequest = WebRequest.Create(#"http://" + APIURL + token + function + param);
var response = await webRequest.GetResponseAsync(); //troubled line
var content = response.GetResponseStream();
StreamReader reader = new StreamReader(content);
result = reader.ReadLine();
if (result == "0")
{
state = "Username is available.";
return UsernameAvailable.Available;
}
else
{
state = "Username is not available.";
return UsernameAvailable.NotAvailable;
}
}
catch
{
state = "Error checking for username.";
return UsernameAvailable.Error;
}
}
I'm going to go on a wild guess here and say that higher up the callstack you're calling usernameAvailable like this:
usernameAvailable().Result
Which is blocking on async code, causing your app to deadlock. This is why you shouldn't block on async code. The reason your answer works is because using ConfigureAwait(false) prevents the synchronization context from following to the continuation, but that is just a dirty workaround which covers up the actual problem of your code.
Instead of doing that, you should also use an async event handler and await on your method as well:
public async void SomeEventHandler(object sender, EventArgs e)
{
await usernameAvailable();
}
Side note - Async methods should have the Async postfix added to them, so your method should actually be named UsernameAvaliableAsync()
Adding .ConfigureAwait(false) to the troubled line fixed the issue and everything works fine now!
old:
var response = await webRequest.GetResponseAsync();
fixed:
var response = await webRequest.GetResponseAsync().ConfigureAwait(false);

Categories

Resources