Task result returning null always - c#

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

Related

Point of Task.Run if it will be awaited immediately

I have this method:
public async Task DoSomething()
{
string token = string.Empty;
await Task.Run(() =>
{
using (var sc = _dbManager.CreateSession())
{
// somework...
}
});
using (var resp = await client.PostAsync(authenticationEndpoint,
new FormUrlEncodedContent(authenticateRequest), stoppingToken))
{
resp.EnsureSuccessStatusCode();
string stringResponse = await resp.Content.ReadAsStringAsync(stoppingToken);
var response = JsonConvert.DeserializeObject<Response>(stringResponse);
token = response.AccessToken;
}
}
Now I do not understand why I need to use await Task.Run? It's confusing for me to understand logic behind this, as I'm awaiting the task to finish anyway, so why should I put it in the Task in the first place?
My lead told me that this was the way to go, and also explained to me that if I don't put that in Task, the code will be executed again from the top, after await client.PostAsync.

How I can call async method in different class?

I have got this code:
public async Task DoRespond(AspNetWebSocketContext context)
{
System.Net.WebSockets.WebSocket socket = context.WebSocket;
while (true)
{
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]);
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
if (socket.State == WebSocketState.Open)
{
string userMessage = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
userMessage = "Message from client : " + userMessage;
buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMessage));
await socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
else
{
break;
}
}
I need to call this async method in different class in bool method (it is an NUnit framework)
protected override bool Test()
{
Websocket ws = new Websocket();
ws.ProcessRequest(context);
Thread.Sleep(1000);
logger.Write("Async method ");
var task = Task.Run(DoRespond);
}
I need to call async Task method in this bool method. How i can do that ? I aslo need call a parametre AspNetWebSocketContext context.
The async..await pattern is contagious and will spread thru your code base.
in order to call the async method, you need to await it in another async method
protected override async Task<bool> Test()
{
using (Websocket ws = new Websocket()) // properly dispose of WebSocket
{
ws.ProcessRequest(context);
await Task.Delay(1000); // notice the awaitable Delay replacing the blocking Sleep.
logger.Write("Async method ");
await DoRespond(context);
}
return true; // not sure where Boolean return value comes from as it wasn't in original method.
}
and, of course, whatever is calling Test() will get similar treatment.
Edit after more information in comments
The test method can be forced to wait for the async method to complete similar to this
protected override bool Test()
{
using (Websocket ws = new Websocket()) // properly dispose of WebSocket
{
ws.ProcessRequest(context);
Thread.Sleep(1000);
logger.Write("Async method ");
var task = DoRespond(context);
task.Wait(); // wait for async method to complete
// assert something?
}
return true; // not sure where Boolean return value comes from as it wasn't in original method.
}
However, do read up on asynchronous testing with NUnit since async test methods (like the first example) have been supported for several years.
For further reading, Async Support in NUnit

ContinueWith not being called async

I'm trying to httpget some values before I execute the next line in the statement. I need to wait for this call to return so I can use the values I deserialize into a list.
Since I want the async call to finish first, I wrapped this in a Task. It worked and it's successfully retrieving the JSON. I then can't get it to go into the ContinueWith block. Why is it not going in there, even when the task is completed(?).
How I'm calling it:
Task f = Task.Run(() =>
{
var task = RetrieveDataAsync();
}).ContinueWith((antecedent) =>
{
pokemonListActivityListView.Adapter = new PokemonListAdapter(this, pokemonList);
pokemonListActivityListView.FastScrollEnabled = true;
pokemonListActivityListView.ItemClick += PokemonListActivityListViewOnItemClick;
});
RetrieveDataAsync method:
private async Task RetrieveDataAsync()
{
string dataUri = "http://pokemonapp6359.azurewebsites.net/Pkmn/GetAllPokemon";
using (var httpClient = new HttpClient())
{
var uri = new Uri(string.Format(dataUri, string.Empty));
//DisplayProgressBar(BeforeOrAfterLoadState.Before, progressBarView);
var response = await httpClient.GetAsync(uri);
//DisplayProgressBar(BeforeOrAfterLoadState.After, progressBarView);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
pokemonList = JsonConvert.DeserializeObject<List<PokemonDTO>>(content);
//canPressButtons = true; //fix this when implement local db
Utilities.Utilities.ShowToast(this, "Successfully fetched data", ToastLength.Short, GravityFlags.Center);
return;
}
else
{
Utilities.Utilities.ShowToast(this, "Failed to fetch data", ToastLength.Short, GravityFlags.Center);
return;
}
}
}
Why is my code not going into the ContinueWith when I've got the JSON ? Thanks!
Instead of just assigning the hot task, you are not waiting on it to finish. You have to call ContinueWith on that task:
var task = RetrieveDataAsync();
task.ContinueWith( ... );
Or await the task:
var result = await RetrieveDataAsync();
... // continue
The problem is that you're ignoring the task returned from RetrieveDataAsync. If you return that task from your lambda expression, then it will behave as you expect.
On a side note, you shouldn't use ContinueWith; it's a dangerous API. Use await instead of ContinueWith:
await Task.Run(() => RetrieveDataAsync());
pokemonListActivityListView.Adapter = new PokemonListAdapter(this, pokemonList);
pokemonListActivityListView.FastScrollEnabled = true;
pokemonListActivityListView.ItemClick += PokemonListActivityListViewOnItemClick;

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.

Strange execution jump when using async/await and System.Threading.Tasks.Parallel

I have the following method:
public async Task ExecuteAsync()
{
Task<IEnumerable<Comment>> gettingComments = RetrieveComments();
Dictionary<string, ReviewManager> reviewers = ConfigurationFacade.Repositories.ToDictionary(name => name, name => new ReviewManager(name));
IEnumerable<Comment> comments = await gettingComments;
Parallel.ForEach(reviewers, (reviewer) => {
Dictionary<Comment, RevisionResult> reviews = reviewer.Value.Review(comments);
int amountModerated = ModerateComments(reviews.Where(r => r.Value.IsInsult), "hide");
});
}
My ModerateComments method looks like the following:
private Task<int> ModerateComments(IEnumerable<Comment> comments, string operation)
{
return Task.Factory.StartNew(() =>
{
int moderationCount = 0;
Parallel.ForEach(comments, async (comment) =>
{
bool moderated = await ModerateComment(comment, operation); //Problem here
if(moderated)
moderationCount++;
}
return moderationCount;
};
}
And finally:
private async Task<bool> ModerateComment(Comment comment, string operation, string authenticationToken = null)
{
if(comment == null) return false;
if(String.IsNullOrWhiteSpace(authenticationToken))
authenticationToken = CreateUserToken(TimeSpan.FromMinutes(1));
string moderationEndpoint = ConfigurationFacade.ModerationEndpoint;
using(HttpRequestMessage request = new HttpRequestMessage())
{
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(moderationEndpoint);
using(HttpResponseMessage response = await _httpClient.SendAsync(request)) //Problem here
{
if(!response.IsSuccessStatusCode)
{
if(response.StatusCode == HttpStatusCode.Unauthorized)
return await ModerateComment(comment, operation, null); //Retry operation with a new access token
else if(response.StatusCode == HttpStatusCode.GatewayTimeout)
return await ModerateComment(comment, operation, authenticationToken); //Retry operation
return false;
}
}
}
return true;
}
I'm having a strange problem at runtime. All the above code is working fine except when it reaches the line:
using(HttpResponseMessage response = await _httpClient.SendAsync(request)) {
//...
}
When I debug my application, this instruction is executed but just after that, it does not throw any exception, nor return anything, it just finish executing and I am derived to the next statement on the Parallel.ForEach loop.
It is really hard to explain so I'll post some images:
All good so far, I reach the following line of code:
The execution keeps going well and I reach the call to the Moderation API
Even if I press F10 (Next statement) in the debugger, the execution flow jumps to the next loop in the Parallel.ForEach loop.
As you can see I have breakpoints in the try-catch just i ncase any exception is thrown, but the breakpoint is never activated, neither is activated the breakpoint in if(moderacion) commentCount++.
So what happens here? Where did my execution flow went? It just dissapears after sending the POST request to the API.
After continuing the execution, all the elements in the enumerable do the same jump, and therefore, my commentCount variable ends up being equal to 0
You don't need Parallel.ForEach or Task.Factory.StartNew to do IO bound work:
private async Task<int> ModerateCommentsAsync(IEnumerable<Comment> comments, string operation)
{
var commentTasks = comments.Select(comment => ModerateCommentAsync(comment, operation));
await Task.WhenAll(commentTasks);
return commentTasks.Count(x => x.Result);
}
Common practice is to add the Async postfix to an async method.
Excellent description for a common problem. Parallel.ForEach does not support async lambdas. async methods return once they hit the first await that would need to block. This happens when you issue the HTTP request.
Use one of the common patterns for a parallel async foreach loop.

Categories