.Net 4.5 Await Breakpoints - vb.net

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).

Related

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

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.

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

.NET Web API, Return Data To Client, Then Process Transaction?

I have a VB.NET Web API controller, that performs two functions: when a request comes in, it processes the request, and then returns data to the client. The client service consuming the process has a timeout of 1.5s, in most cases my controller responds in time, however under some circumstances the controller does not respond in time.
According to telemetry the heavy lifting that will cause it to take to long to return can actually be processed after i return to the client, I've tried to modify the controller, but this has not improved the response time:
Public Class SMSController
Inherits TwilioController
<HttpPost>
Public Async Function Index() As Threading.Tasks.Task(Of ActionResult)
Dim tml = New MessagingResponse()
If String.IsNullOrEmpty(Request.Form("From")) Then Return TwiML(tml.Message(Constants.smsError))
Dim smsFrom As String = Replace(Request.Form("From"), "+1", "")
Dim db As New DB_ENTITY
Dim r = (From p In db.Task Where p.smsFrom = smsFrom).FirstOrDefault()
If IsNothing(r) Then
Try
Return TwiML(tml.Message(Constants.smsError))
Finally
HeavyLifting()
End Try
End If
'// Code shortened for brevity
It is my understanding that this should return the twilio markup to the client, then run the heavylifting() but this does not seem to be the case.
The heavy stuff returns in time the majority of the time, so i don't want to task it and process it later, is there a better way i can return the markup to the client and then perform the processing?

Why Async function returning System.Threading.Tasks.Task`1[System.String]?

I have a VB.NET function as below:
Public Shared Async Function GetIdDoc() As Task(Of String)
Dim result As String = ""
'Dim Uri As String = "http://localhost:53917/api/Documenti/GetNextIdDocumenti"
Dim Uri As String = apiUri & ApiEndPoints.GetNextIdDocumenti
Using client = New HttpClient()
Using response = Await client.GetAsync(Uri)
If response.IsSuccessStatusCode Then
Dim DocumentiIDJsonString = Await response.Content.ReadAsStringAsync()
result = DocumentiIDJsonString.ToString()
End If
End Using
End Using
Return result
End Function
I'm trying to return the Document ID from the DB but I'm getting
System.Threading.Tasks.Task`1[System.String]
Where actually it should return "2". Please help me on this: what am I doing wrong with this function?
Update
here is the function called:
txtIDDoc_Detail.Text = ApiData.GetIdDoc().ToString()
But inside the textbox I'm getting the above text. thanks.
I'm from C# but should work the same. In newer .Net Versions (>= 4.5) async/await is implemented. So if a method is marked as async and returns a Task (which should always be the case), you need to await it. This implicate that you have to mark your Method as async too. So your call should look like this:
txtIDDoc_Detail.Text = await ApiData.GetIdDoc();
The await waits till the long running Task is ready and returns it's inner value. All async Methods should return Task. If the Method is void it would be Task. Else it could be Task<int> or any other type. So await it and you can keep running ;)
#Sebi gives a great explanation of how to properly use async and await in this case, but I'm going to expand on exactly why you are getting the result that you see.
txtIDDoc_Detail.Text = ApiData.GetIdDoc().ToString()
Is returning
System.Threading.Tasks.Task`1[System.String]
Because you are calling .ToString on the instance of the Task Task(Of String), not the actual result. Types that don't override .ToString inherit the behavior of Object, which just returns the name of the type as a string.
You probably want this (asynchronous call):
txtIDDoc_Detail.Text = await ApiData.GetIdDoc()
Or this (synchronous call):
txtIDDoc_Detail.Text = ApiData.GetIdDoc().Result
Either of these calls will actually result of the task after it has completed.

Can somebody give me an example of getting the content of a page from a URL in vb.net for windows 8?

I am very new to vb/.net and I'm trying to do something that I can do easily in classic vb. I want to get the source html for a webpage from the URL.
I'm using vb.net in Visual Studio Express for Windows 8.
I've read loads of stuff that talk about HttpWebRequest, but I can't get it to work properly.
I did at one point have it returning the html header, but I want to content of the page. Now, I can't even get it back to giving me the header. Ultimately, I want to process the html returned which I'll do (to begin with) the old-fashioned way and process the returned html as a string, but for now I'd like to just get the page.
The code I've got is:
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create(New Uri(URL))
txtHTML.Text = request.GetRequestStreamAsync().ToString()
Can anyone help me with an example to get me going please?
You're trying to use an Async method in a synchronous way, which won't make any sense. If you're using .NET 4.5, you can try marking the calling method with Async and then using the Await keyword when calling GetRequestStreamAsync.
Public Sub MyDownloaderMethod()
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest
= System.Net.HttpWebRequest.Create(New Uri(URL))
' Use the Await keyword wait for the async task to complete.
Dim response = request.GetResponseAsync()
txtHTML.Text = response.GetResponseStream().ToString()
End Function
See the following MSDN article for more information on async programming with the Await keyword: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
Edit
You are receiving your error because you're trying to get the Request stream (what you send the server), and what you really want is the Response stream (what the server sends back to you). I've updated my code to get the WebResponse from your WebRequest and then retrieve the stream from that.
Public Shared Function GetWebPageString(ByVal address As Uri) As String
Using client As New Net.WebClient()
Return client.DownloadString(address)
End Using
End Function
There is also DownloadStringAsync if you don't want to block
request.GetRequestStreamAsync() is probably not a method. I think you're cribbing code from a site where someone wrote their own add-on methods to HttpWebRequest. Try request.GetResponse() to return a response object, then in the response object you can inspect the stream and convert it to text if you need to.
This worked for me in VB.Net 4.5
Public Async Sub GetHTML()
Dim PageHTML as string
Dim client As New HttpClient
Dim getStringTask As Task(Of String) = client.GetStringAsync(PageURL)
PageHTML = Await getStringTask
MsgBox(PageHTML)
End Sub