VB .net Using Async and Await with while true loop locks UI - vb.net

I have a VB.net winform app that I am writing with a WebSocketClient, I have been searching for days to find some documented answers to this specific question but not found anything that I can use.
My Async/await class that is used to talk to the remote server uses a number of await statements, mainly sendasync and receiveasync. The app is similar in functionality to SignalR chat type applications.
I successfully connect to the URI, receive a welcome message and authenticate, still using Async/Await. The button on the form that starts the WebSocketClient is also converted to an async method with the WebSocketClient "awaited".
Then I drop into a while/true loop which should allow the user to send requests and receive feedback from the remote server.
The problem I have is that the UI locks and when the user tries to send a request from a button click is completely unresponsive.
I have managed to get some modicum of success with background workers but I want to use the Async/Await method as it is widely considered to be a more modern approach.
I cannot work out how I get an Async/await structure to emulate the while loop unless I have my final await implementing a while loop which I am sure goes against the design of Async/await and will also probably lock up as well.
Can anyone help me passed this hurdle please?
thanks all,
jON
While True
If jsonRequestText <> "" Then
jsonResponseText = Encoding.UTF8.GetString(bytesReceived.Array, 0, result.Count)
bytesToSend = New ArraySegment(Of Byte)(Encoding.UTF8.GetBytes(jsonRequestText))
Await ws.SendAsync(bytesToSend, WebSocketMessageType.Text, True, Threading.CancellationToken.None)
bytesReceived = New ArraySegment(Of Byte)(New Byte(1023) {})
result = Await ws.ReceiveAsync(bytesReceived, Threading.CancellationToken.None)
jsonResponseText = Encoding.UTF8.GetString(bytesReceived.Array, 0, result.Count)
jsonRequestText = ""
End If
If jsonResponseText <> "" Then
Await ConsumeResponseAsync(jsonResponseText)
jsonResponseText = ""
End If
End While
I am using websocketclient and once I connect and authenticate I drop into the posted loop. I am struggling to work out how I replicate this loop with an async await approach i.e. without while/true.

Related

Running data downloading on background thread

Im building a new app and since i want it to be smooth as everyone, I want to use a background thread that would be responsible for all the data downloading using restsharp. Im also following the MVVM pattern.
I've been reading a lot about task.run and how to use it properly and the whole async-await topic. But since Im new to all this, Im not sure how I should procceed to do things right. I have a lot of code so I will breifly try to explain what Im doing and then put a snippet.
So I started with creating a service class that contains all the functions that are using restsharp to get the data. And inside my ViewModel Im calling those functions in the very begining. Im trying to use tasks and run those functions on the background thread but the app get blocked on the splash screen. And abviously thats because Im doing things wrong ... so I decided to ask you guys.
I have this function for exemple :
public string GetResPor()
{
var restClient = new RestClient { BaseUrl = new Uri("http://xxx.xxx.xxx.xxx:xxxx") };
var request = new RestRequest
{
Resource = "getCliPor",
Method = Method.GET
};
request.AddParameter(new Parameter { Name = "idt", Value = GetImAsync().GetAwaiter().GetResult(), Type = ParameterType.GetOrPost });
var result = restClient.Execute(request);
Port = result.Content;
return Port;
}
When I convert this on a Task :
public async Task<string> GetResPor()
{
var restClient = new RestClient { BaseUrl = new Uri("http://xxx.xxx.xxx.xxx:xxxx") };
var request = new RestRequest
{
Resource = "getCliPor",
Method = Method.GET
};
request.AddParameter(new Parameter { Name = "idt", Value = GetImAsync().GetAwaiter().GetResult(), Type = ParameterType.GetOrPost });
var result = await restClient.ExecuteTaskAsync(request);
Port = result.Content;
return Port;
}
on the ViewModel I start by creating a new instance of my service class and then:
Port = RD.GetRestauPort().GetAwaiter().GetResult();
And this is where the app get blocked, no exceptions no nothing.
To keep things simple, let's start with the basics. The easiest thing to do, in order to run something in a background thread, is to call it inside a Task.Run(). What this does is:
Queues the specified work to run on the ThreadPool and returns a task or Task<TResult> handle for that work.
Basically, you are delegating your work to the TreadPool and it handles everything for you - looks for a worker, waits for the worker to finish its job (on a new thread) and then notifies you of the result.
So, basically, whatever you want to be in a background thread, the simples solution will be to wrap it inside a Task.Run() and await its result, in case you need it.
Also, avoid using GetAwaiter().GetResult(). The simple rule in asynchronous programming is - if you can await, await all the way up.
You can read more about the topics in
this SO post
Advanced Tips for Using Task.Run With Async/Await
Using Task.Run in Conjunction with Async/Await

Ignore user input while Uploading to FTP

I'm developing a windows store app, and I'm uploading a file to an FTP server with WebRequest, since it was the only work around I could find, with the limitations that I had.
When the application is uploading the video, which takes a few minutes, if the user taps the screen the app will crash. If no input is made, it will work fine.
When I was using Alex Pilotti's FTPS Client DLL, this didn't happen, but I couldn't get the certification for windows store using this DLL.
In my PC, this doesn't happen. It will wait until the video is uploaded and then execute the user input, but in the tablet it's a different story, maybe because it has less processing power/memory, it just crashes.
I was thinking: maybe there is a way to ignore all user input while the upload is happening.
I know it's not the best way, to take control from the user like that, but it would do the job and it would only be for a few minutes.
I've been googling, but I can't find a way to do this.
I'll leave my code below, just in case:
Public Async Function uploadFile(filename As String, file As StorageFile) As Task(Of Boolean)
Try
Dim ftpURL As String = "ftp://111.22.33.444"
Dim request As WebRequest = WebRequest.Create(ftpURL + "/" + filename)
request.Credentials = New NetworkCredential("user", "pass")
request.Method = "STOR"
Dim buffer As Byte() = Await ReadFileToBinary(filename, file)
Dim requestStream As Stream = Await request.GetRequestStreamAsync()
Await requestStream.WriteAsync(buffer, 0, buffer.Length)
Await requestStream.FlushAsync()
Return True
Catch ex As Exception
Return False
End Try
End Function
I fixed this issue with a very simple line of code:
Await Task.Run(Function() uploadFile(filename, file))
Worked for me.

How do you configure a client to auto-answer within vLine?

What is the correct method for setting a client to auto answer with the vLine API for WebRTC calls?
Looking at your comment, it looks like you have figured this out. But for completeness and for future reference I will go ahead and answer.
To auto answer a call, all you have to do is call MediaSession.start() when an incoming call comes in, instead of throwing a prompt to the user.
Here is an example snippet:
client.on('add:mediaSession', onAddMediaSession, self);
// Handle new media sessions
onAddMediaSession(event){
var mediaSession = event.target;
mediaSession.on('enterState:incoming', onIncoming, self);
},
// Handle new incoming calls and autoAccept
onIncoming(event){
var mediaSession = event.target;
// Auto Accept call instead of a prompt
mediaSession.start();
}
Note that you can do this in your code even if you are using the UI Widgets.

.Net 4.5 Await Breakpoints

I couldn't find a full example for PostAsync so I had to piece one together. Therefore, I am not sure if what I am viewing is a limitation with the debugger or I simply did it wrong.
This is what I am trying to do:
I have to go through a list and make a web service call for each item on the list. My thought is that I could use the new 4.5 async stuff to keep it flowing without blocking during each call to the web service.
I've done a tone of research and watched Jon Skeet's video on TekPub, but I'm still not sure if I am doing this correctly. That is, when I set break points my async method never returns control to the caller. It basically seems to go along exactly as my synchronous version.
Question:
Is it normal for the debugger to appear synchronous or does that indicate my code is not implemented correctly?
Here is my Post method:
Public Async Function PostSecureXMLAsync(ByVal username As String, ByVal password As String, ByVal XMLtoSend As String) As Task(Of String)
Dim content = New StringContent(XMLtoSend, Encoding.UTF8, "text/xml")
Dim credentials = New NetworkCredential(username, password)
Dim handler = New HttpClientHandler() With {.Credentials = credentials}
Using client = New HttpClient(handler)
Using response = client.PostAsync(APIurl, content).Result
Return Await response.Content.ReadAsStringAsync()
End Using
End Using
End Function
This is how it is being used:
For Each ListItem In ListObj
...
Result = XMLExchangeObj.PostSecureXMLAsync(Username, Password, Payload).Result
...
Next
I was expecting control to return to the For Each loop while it was waiting for replies from the Web Service, but based on my break points it seems to be running synchronously.
When you're working with Async, you don't want to call Wait or Result. Instead, you should use Await. I see one Result in PostSecureXMLAsync:
Using client = New HttpClient(handler)
Using response = Await client.PostAsync(APIurl, content) ' Changed to Await
Return Await response.Content.ReadAsStringAsync()
End Using
End Using
And there's another one when you call your Async method:
Result = Await XMLExchangeObj.PostSecureXMLAsync(Username, Password, Payload)
This does mean that your calling method must also be Async, which means any methods that call that method should use Await, and must also be Async, etc. This "growth" through your code is perfectly normal. Just allow Async to grow until you reach a natural stopping point (usually an event handler, which you can make Async Sub).

Appication goto Freeze when downloading a webpage

i wrote a function for download a webpage : function like:
public string GetWebPage(string sURL)
{
System.Net.WebResponse objResponse = null;
System.Net.WebRequest objRequest = null;
System.IO.StreamReader objStreamReader = null;
string sResultPage = null;
try
{
objRequest = System.Net.HttpWebRequest.Create(sURL);
objResponse = objRequest.GetResponse();
objStreamReader = new System.IO.StreamReader(objResponse.GetResponseStream());
sResultPage = objStreamReader.ReadToEnd();
return sResultPage;
}
catch (Exception ex)
{
return "";
}
}
But my problem is that. when this function working at that time application goto freeze (not response) and that time my can't not do any thing. How can i solve this problem. when downloading at time user can do other thing in my application.
Welcome to the world of blocking IO.
Consider the following:
You want your program to download a web page and then return the first 10 letters it finds in the source html. Your code might look like this:
...
string page = GetWebPage("http://example.com"); // download web page
page = page.Substring(0, 10);
Console.WriteLine(page);
....
When your program calls GetWebPage(), it must WAIT for the web page to be fully downloaded before it can possibly try to call Substring() - else it may try to get the substring before it actually downloads the letters.
Now consider your program. You've got lots of code - maybe a GUI interface running - and it's all executing line by line one instruction at a time. When your code calls GetWebPage(), it can't possibly continue executing additional code until that request is fully finished. Your entire program is waiting on that request to finish.
The problem can be solved in a few different ways, and the best solution depends on exactly what you're doing with your code. Ideally, your code needs to execute asynchronously. c# has methods that can handle a lot of this for you, but one way or another, you're going to want to start some work - downloading the web page in your case - and then continue executing code until your main thread is notified that the webpage is fully downloaded. Then your main thread can begin parsing the return value.
I'm assuming that since you've asked this question, you are very new to threads and concurrency in general. You have a lot of work to do. Here are some resources for you to read up about threading and implementing concurrency in c#:
C# Thread Introduction
.NET Asynchronous IO Design
the best was is to use thread
new Thread(download).Start(url);
and if your download page size is large use chunk logic.
HttpWebRequest ObjHttpWebRequest = (HttpWebRequest)HttpWebRequest.Create(Convert.ToString(url));
ObjHttpWebRequest.AddRange(99204);
ObjHttpWebRequest.Timeout = Timeout.Infinite;
ObjHttpWebRequest.Method = "get";
HttpWebResponse ObjHttpWebResponse = (HttpWebResponse)ObjHttpWebRequest.GetResponse();
Stream ObjStream = ObjHttpWebResponse.GetResponseStream();
StreamReader ObjStreamReader = new StreamReader(ObjStream);
byte[] buffer = new byte[1224];
int length = 0;
while ((length = ObjStream.Read(buffer, 0, buffer.Length)) > 0)
{
downloaddata += Encoding.GetEncoding(936).GetString(buffer);