Beginner about async/Task - c#

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

Related

Task result returning null always

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

how to wait for await in async method to finish the all the executions?

For the following code im calling that async void method.
public void LoadSystemDetails(int clientId)
{
DataSystem.Name = "Salesforce System";
DataSystem.Description = "";
GetAllFields(clientId);
}
following code is GetAllFields method
public async void GetAllFields(int clientId)
{
this.DataSystem.SystemTables = new List<DataSystemTable>();
using (var forceClient = await ConnectToSalesforceByOAuth(clientId))
{
var SalesForceTable = new DataSystemTable
{
TableName = "Contact"
};
DataSystem.SystemTables.Add(SalesForceTable);
var contact = forceClient.DescribeAsync<SalesforceObject>("Contact");
var tableFields = new List<DataSystemField>();
foreach (var con in contact.Result.Fields)
{
tableFields.Add(new DataSystemField
{
ColumnName = con.Name,
});
}
SalesForceTable.EissSyncSystemFields = tableFields;
}
and i call callbackScript as below.
callbackScript.AppendLine(string.Format("var destinationSystem ={0};", JsonConvert.SerializeObject(this.DestinationSystem, Formatting.Indented)));
here DestinationSystem is calling the LoadSystemDetails. Like DestinationSystem.LoadSystemDetails(clientId)
while using (var forceClient = await ConnectToSalesforceByOAuth(clientId)) line is execute at the time the callbackScript is executed. so the SystemTables doesn't have any value. but it having Name and Description.
so here i need to wait the LoadSystemDetails to finish the GetAllFields.
How i do that.Please help me.
Thanks.
If you need LoadSystemDetails to wait for GetAllFields, there are 2 problems here:
you are calling async method from a synchronous context
GetAllFields is async void, which means fire and forget. You will never be able to wait for it to finish.
Solution:
First, NEVER use async void if you need to wait for the result or end. Use async Task instead
Second, either convert LoadSystemDetails to async method also, then await the GetAllFields (that should return Task), or use GetAllFields(clientId).Wait()
take a look at this article for more information on async/await: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
As #netchkin already said: Never use async void. Use async Task. You don't have to return a Task yourself, you can still use return;

Get JSON string with httpClient

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.

Converting a series of synchronous methods into async in C#

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.

Async lambda expression with await returns Task?

I have the following code:
// Get all of the files from the local storage directory.
var files = await folder.GetFilesAsync();
// Map each file to a stream corresponding to that file.
var streams = files.Select(async f => { return await f.OpenStreamForWriteAsync(); });
I would expect streams to be of type IEnumerable<Stream> but in fact it is of IEnumberable<Task<Stream>>, which is what I would've expected had I omitted the await keyword. The return type of OpenStreamForWriteAsync is Task<Stream> — surely awaiting it should produce a Stream?
So, why is the return await statement returning a Task?
Thanks for your help.
All async methods return either void, Task, or Task<TResult>. The lambda is just an anonymous method, and thus that still applies. It's essentially the same as this named method:
private static async Task<Stream> Foo(TypeGOesHere f )
{
return await f.OpenStreamForWriteAsync();
}
In order to make it return a Stream it would need to be a blocking method, rather than an async method:
private static Stream Foo(TypeGOesHere f )
{
return f.OpenStreamForWriteAsync().Result;
}
You probably don't want that.
You can turn your IEnumerable<Task<Stream>> into a Task<Stream[]> by using Task.WhenAll if that helps you:
Task<Stream[]> resultTask = Task.WhenAll(streams);
Wouldnt this be the best solution?
// Get all of the files from the local storage directory.
var files = await folder.GetFilesAsync();
// Map each file to a stream corresponding to that file and await the Task that waits for all tasks to complete? maybe thats whats being implied above...
var streams = await Task.WhenAll(files.Select(async f => { return await f.OpenStreamForWriteAsync(); }));

Categories