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

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?

Related

How to get return value from function used in thread in vb. Net

Public function myfn1(byval pRequest as string) as string
Dim param(1) object
param(0)=pRequest
Dim T as new thread(Addresof myfn2)
T. Start(param)
End function
Private function myfn2(byval pReq as string) as string
'////some stuff here////
Return lstrResponse
End function
Here myfn1 is accepting requests from user. Sometimes the requests may be concurrent at a time. So I have used thread in myfn1. Myfn2 is actually processing the request and returning the response. So I am willing to get that response in myfn1 after the thread processed the task. What should I do? Or is there any other way out, Pls suggest
You should look into using the Async/Await structure : https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/concepts/async/
For Doing CPU bound work on a separate thread there are a couple options. I like using Task.Run() doc here: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run?view=netframework-4.8
You can awaitthe task you create and get the result when it's done like:
SomeVariable = Await Task.Run(Function() FunctionName)

ASP MVC async Controller and HttpContext.Cache - Correct Pattern?

Given an async action method on an ASP MVC Controller and an async method that gets some data:
public async Task<ActionResult> Index()
{
var apiClient = new apiClient();
var data = await apiClient.GetDataAsync(id);
I want GetDataAsync to store the result as a Cache item, so it doesn't have to request from an external api next time.
I can sometimes get this to work by passing in a reference to the cache object, (often inexplicably null even though passed from what I thought was the starting thread. Must not be the starting thread I guess?).
var data = await apiClient.GetDataAsync(id, System.Web.HttpContext.Current.Cache);
But I seem to remember that this is not a good idea (something to do with thread safety).
What is the recommended way to handle caching in an async method? Should I move cache handling into the controllers? Seems a shame as it made sense for the cache management to happen closer to the data source.

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

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

Building workaround for HttpWebRequest timeout issue

I'm using the HTTP Web Request class to call a RESTful web service. I need to pass data and receive data and it all seems to work very well. Today I attempted to configure the time-out of the class because there is a high likelihood of the server running the service being offline and I don't want to waste time waiting. I configured it all but it seemed to make no difference. The call still waited over 10 seconds before failing.
On looking into it I found that the time-out only deals with the processing of the call and that the DNS lookup beforehand is not included. As this would be the problem it would make sense as to why the time-out wasn't working as I'd expected.
Further reading suggested using the HttpWebRequest class in an asynchronous style instead. I've had a look at the code to do so but don't understand how to retrieve the callback in my code which is effectively synchronous.
The code I have as follows is as so:
HttpWebRequest _serviceRequest = (HttpWebRequest)WebRequest.Create(new Uri("http://mywebservice.com"));
_serviceRequest.Timeout = 3000;
HttpWebResponse response = (HttpWebResponse)_serviceRequest.GetResponse();
XmlReader reader = XmlReader.Create(response.GetResponseStream(), set);
The code I have to call asynchronously ends with the following line, but I'm not sure as to what I should do to get the response object.
IAsyncResult result = (IAsyncResult)req.BeginGetResponse(new AsyncCallback(RespCallback), reqState);
I'm also concerned about a half baked asynchronous solution such as this. Is it good practice to use an asynchronous method through a synchronous piece of code.
Any helpers appreciated...
The response would be available when the callback function RespCallback is invoked. I don't know what reqState has, but I assume it contains a reference to the original HttpWebRequest object. If this is the case, this would be a simple implementation of the RespCallback method:
void RespCallback(IAsyncResult asyncResult)
{
ReqState reqState = (ReqState)asyncResult.AsyncState;
HttpWebResponse resp = (HttpWebResponse)reqState.Request.EndGetResponse(asyncResult);
// do what you need with the response.
}
Update: more info as asked in the comment
If you want the response in the same method where you did the Begin call, you can have an event which will be set when the callback is received, and you can wait on that event after the Begin call, like in the example below
class ReqState {
public HttpWebRequest Request { get; set; }
public HttpWebResponse Response { get; set; }
public AutoResetEvent Evt { get; set; }
}
void RespCallback(IAsyncResult asyncResult) {
ReqState reqState = (ReqState)asyncResult.AsyncState;
reqState.Response = (HttpWebResponse)reqState.Request.EndGetResponse(asyncResult);
reqState.Evt.Set();
}
void CallMethod() {
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(...);
// set properties on req
ReqState state = new ReqState();
state.Request = req;
state.Evt = new ManualResetEvent(false);
req.BeginGetResponse(RespCallback, state);
state.Evt.WaitOne(TimeSpan.FromSeconds(30)); // wait for 30 seconds
// access response via state.Response
}
Now notice that you're essentially doing a synchronous call in an asynchronous way. That gives you more control over the timeout, but with the price of code complexity. Another thing, this will not work on platforms such as Silverlight (and Windows Phone, IIRC), where synchronous calls (even those dressed up as asynchronous) are forbidden.