I am using Xamarin Forms and I am trying to get a JSON string for a file located here. However I do not seem to be able to get the Json string out. This is my code:
public async static Task<string> GetJson(string URL)
{
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(URL))
using (HttpContent content = response.Content)
{
// ... Read the string.
return await content.ReadAsStringAsync();
}
}
private static void FindJsonString()
{
Task t = new Task(GetJson("https://dl.dropboxusercontent.com/u/37802978/policyHolder.json"));
t.Start();
t.Wait();
string Json = t.ToString();
}
What am I doing wrong?
I get these 2 Errors in relation to this line
Task t = new Task(GetJson("https://dl.dropboxusercontent.com/u/37802978/policyHolder.json"));
Error 1
The best overloaded method match for 'System.Threading.Tasks.Task.Task(System.Action)' has some invalid arguments
Error 2
Argument 1: cannot convert from 'System.Threading.Tasks.Task' to 'System.Action'
That is because new Task is expecting an Action delegate, while you pass it a Task<string>.
Don't use new Task, use Task.Run. Also, note that you're passing in an async method, you might want to await GetJson:
So you either need
var task = Task.Run(() => GetJson("https://dl.dropboxusercontent.com/u/37802978/policyHolder.json"));
Or if you want to await inside Task.Run:
var task = Task.Run(async () => await GetJson("https://dl.dropboxusercontent.com/u/37802978/policyHolder.json"));
They will also differ in return type. The former will return a Task<Task<string>>, while the latter will return Task<string>
TPL guidelines state async method should end with a Async postfix. Consider renaming GetJson to GetJsonAsync.
Related
I have Receive method in the class WebSocket
public async Task<string> Receive()
{
byte[] buffer = new byte[1024];
string response = string.Empty;
while (_socket.State == WebSocketState.Open)
{
var result = await _socket.ReceiveAsync(new ArraySegment<byte>(buffer), new CancellationToken(false));
if (result.MessageType == WebSocketMessageType.Close)
await _socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
else
{
response = Encoding.UTF8.GetString(buffer).TrimEnd('\0');
}
}
return response;
}
Calling Receive method from object wb as below:
async Task<string> OnMessageReceive()
{
return await Task.Run(() => wb.Receive());
}
Expecting to receive the response but always get null as part of Result.
var msg = OnMessageReceive();
Console.WriteLine(msg.Result);
Difficult to figure out why Result is not returning string data!.
Solution (Uploaded to github repo)
I think it is because you are calling a async method without await so it won't wait for complete the execution of your code
async Task<string> OnMessageReceive(){....}
var msg = OnMessageReceive(); // you need to use await key word to call this method
Couple of changes and you should be good to go.
First -
async Task<string> OnMessageReceive()
{
return await wb.Receive();
}
Second -
var msg = await OnMessageReceive();
Console.WriteLine(msg);
Hope this helps.
I got the answer :)
The problem was with while loop. Below line of code was getting executed in loop and while second call ReceiveAsync method get re-execute and loop exits with re-initialization of response variable.
var result = await _socket.ReceiveAsync(new ArraySegment<byte>(buffer), new CancellationToken(false));
Also I refer below resource:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/async-return-types
I'm really looking for the solution and can't find proper instruction.
I have async method in RestService.cs
public async static Task<List<Convert>> CheckBTCUSDAsync()
{
HttpClient client = new HttpClient();
string restUrl =
"https://bitbay.net/API/Public/BTCUSD/trades.json";
HttpResponseMessage responseGet = await
client.GetAsync(restUrl);
if (responseGet.IsSuccessStatusCode)
{
var response = await responseGet.Content.ReadAsStringAsync();
List<Convert> currencies = Convert.FromJson(response);
//Debug.WriteLine(currencies[0].Date);
return currencies;
}
else
{
//Debug.WriteLine("***************");
//Debug.WriteLine("*****FALSE*****");
//Debug.WriteLine("***************");
return null;
}
}
I want to use it in my MainPage but of course I cant use await in sync method. I found that some devs suggest putting async tasks in eg OnStart method: https://xamarinhelp.com/xamarin-forms-async-task-startup/
I need to to Bind the returned list to picker in Xaml but of course when trying to use:
var convert = RestService.CheckBTCUSDAsync().Result;
It hangs the UI thread. Anyone knows what is the best/easiest way to resolve this?
This is how I got it to work on my app
var convert = Task.Run(() => RestService.CheckBTCUSDAsync()).Result;
I was reading the following topic http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
and decided to write a common utility method in my library to do a GET on remote url via HTTPClient
public static async Task<T> GetAsync<T>(HttpGetObject getObject)
{
string baseUrl = getObject.BaseUrl;
string actionUrl = getObject.ActionRelativeUrl;
string acceptType = getObject.AcceptType;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptType));
AddCustomHeadersToHttpClient(client, getObject);
// HTTP GET
HttpResponseMessage httpResponseMessage = await client.GetAsync(actionUrl).ConfigureAwait(false);
if (httpResponseMessage.IsSuccessStatusCode)
{
T response = await httpResponseMessage.Content.ReadAsAsync<T>().ConfigureAwait(false);
return response;
}
else
{
string message = httpResponseMessage.Content.ReadAsStringAsync().Result;
throw new Exception(message);
}
}
return default(T);
}
I know the "await httpResponseMessage.Content.ReadAsAsync().ConfigureAwait(false)" will prevent the deadlock in the above code
First:
My query is for "string message = httpResponseMessage.Content.ReadAsStringAsync().Result" line, will .Result can cause deadlock or not in that line?
Second:
If I call that code from UI like this:
public static object DoGet()
{
// Build getObject
var task = Utility.GetAsync(getObject);
task.Wait();
var response = task.Result;
return response;
}
Will that cause a deadlock?
Please note that I know to avoid all the mess with async-await, all the methods from UI to DAL must be async-await but I am not in position at this moment to change all that structure, my goal at this moment is to call HttpClient library and do a few GET operations.
So my questions is that will the above code can cause a deadlock?
Third:
Is task.Wait(); even needed in the above code?
In the general case, you should assume that yes, calling .Result or .Wait() on anything awaitable is dangerous and can deadlock (unless you are the library issuing the task, and you understand the full context). It is possible that it will work OK in some specific cases, but you should not rely on that behaviour, even if it works today.
Have a look at this code:
private async void Lista()
{
var _folder = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await _folder.GetFileAsync("thefile.txt");
var read = await Windows.Storage.FileIO.ReadTextAsync(file);
}
Since the codeblock contais await i need to use async in the signature. This means that I cant simply add "Retrun read" at the end. (which is what i would like to get back from the method.)
From what I can understand i need to use task somehow. Any tips on how to retrieve the var read?
You can change the returns type as Task<string>
private async Task<string> Lista()
{
var _folder = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await _folder.GetFileAsync("thefile.txt");
var read = await Windows.Storage.FileIO.ReadTextAsync(file);
return read;
}
From MSDN
An async method can have a return type of Task, Task<TResult>, or void. [...]
You specify Task<TResult> as the return type of an async method if the return statement of the method specifies an operand of type TResult. You use Task if no meaningful value is returned when the method is completed. That is, a call to the method returns a Task, but when the Task is completed, any await expression that's awaiting the Task evaluates to void.
You need to change your return type to Task of T where T is your intended return type, in this case string.
private async Task<string> Lista()
{
var _folder = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await _folder.GetFileAsync("thefile.txt");
var read = await Windows.Storage.FileIO.ReadTextAsync(file);
return read;
}
If you change your return method signature to
private async Task<T> Lista()
Where T is the type returned by ReadTextAsync method then you should be able to return it.
It will then have to be awaited by the invoking method. Or the invoking method will have to "unwrap" it using .Result.
So assuming that ReadTextAsync returns string you can try something like that:
private async Task<string> Lista()
{
var _folder = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await _folder.GetFileAsync("thefile.txt");
return await Windows.Storage.FileIO.ReadTextAsync(file);
}
How do I convert this chain of synchronous method calls into async (using the async/await operators)? Given that only the last call, DoRequest(), is the one that takes time to execute, is that the only method that needs to become async? Or do all the callers in the chain, RequestSomething() and Process(), need to be made async as well?
[HttpGet]
void Process()
{
var url = "http://someapi.com";
var myObject= RequestSomething(url);
//do something with the myObject.
}
MyObject RequestSomething(string url)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
var response = DoRequest(request);
return JsonConvert.DeserializeObject<MyObject>(response);
}
//method that takes time to return.
HttpResponseMessage DoRequest(HttpRequestMessage request)
{
var client = new HttpClient();
return client.SendAsync(request).Result;
}
To do async correctly it is "infectious", if you do it in one spot you need to do it all the way up the call chain to get any of the real benefits out of it. So whatever is calling Process() will need to handle the task returned from Process by either awaiting it or passing it up the chain like DoRequest does.
async Task Process()
{
var url = "http://someapi.com";
var myObject= await RequestSomething(url);
//do something with the myObject.
}
async Task<MyObject> RequestSomething(string url)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
var response = await DoRequest(request).ConfigureAwait(false);
return JsonConvert.DeserializeObject<MyObject>(response);
}
//method that takes time to return.
Task<HttpResponseMessage> DoRequest(HttpRequestMessage request)
{
var client = new HttpClient();
return client.SendAsync(request);
}
Because you do not do any extra work after performing the request you don't need async/await in your DoRequest function, but the other ones will need the async/await keywords. The .ConfigureAwait(false) makes it so that function does not have to run the rest of its code on the UI thread, this can give you a small performance boost. I did not know if the code that is in //do something with the myObject. required you being on the UI thread or not, so I did not put it on that await, but if you don't need to be on the UI thread you could add it there too.
You should make DoRequest...
Public async Task<HttpResponseMessage> DoRequest(...
Then return await client.SendAsync
Similarly, DoSomething should be async Task<...>
Your calling method, Process can be async void if you want to call it as fire and forget, otherwise an async Task.
Try:
var task = Task.Run(() => RequestSomething());
var task2 = Task.Run(() => RequestSomethingElse());
await Task.WhenAll(task, task2);
You can specify more than two if you like, or only one.