I have a VB.Net page that needs to submit data to a url after a user clicks a button. I don't need any data back from the url, I just need to pass parameters to it and allow the user to continue to the next step without waiting for the url to do it's thing.
I've seen some similar posts for c# using UploadStringTaskAsync, but haven't been able to find a corresponding method for VB.net.
https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.uploadstringtaskasync?view=net-6.0
I believe I can call the Async method from my existing nonasync methods as I don't need the response back. However, if there is a more elegant approach to do this please let me know.
Update with current code attempting to use thread:
Sub Page_Load(sender As Object, e As EventArgs)
If Not IsPostBack Then
Dim thread As New Thread(AddressOf testSub)
thread.Start()
End If
End Sub
Sub testSub
Using WC As New WebClient WC.UploadString("https://someurl.com?parameter1=testing¶meter2=anothertest", "SOMEDATA")
End Using
End Sub
This runs but unfortunately does not appear to handle any of the parameters. When I post the url directly in the browser it runs as expected. I don't need to send any data other than the querystring as well so I'm not sure if that's breaking the uploadstring. However, when I run it via debugger I don't see any errors so long as I populate that string for the data with a value.
I might be misunderstanding though when the await call is needed. While I don't need any data back, the external url can take up to 5 minutes to process. I'm wondering if it's taking too long and timing out after that thread is started.
You could run it in its own thread.
Imports System.Net
Imports System.Threading
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
' Create a thread to run this in the background
Dim t As New Thread(
Sub()
Using WC As New WebClient
WC.UploadString("https://YOURURL", "YOURDATA")
End Using
End Sub
)
' Start the thread
t.Start()
End Sub
End Class
Related
i'm writing for ask this community the best way for able my software not block during long operation over file multiselection.
My software analyse 1 to n PDF and for every file read all pages. for every page read all lines and for all line analyse data following string algorithm.
In case user load many PDF file the process could be long and could freeze application.
I ask to you the best way for deny freeze in my application.
On this site i read about ASYNC method or Thread sleep function and much other, but i don't understand which is best to use.
Initially i simply thought about a wait timer between file analyse, but this extend time of operation and maybe not deny freeze, which depend on CPU load and file complexity.
***** UPDATE CODE *****
Here a little schema code of my test using Async method...
Private Async Sub cmdParsePDF_Click(sender As Object, e As EventArgs) Handles cmdParsePDF.Click
Await Task.Run(Sub()
ParsePDF(textboxType.text)
End Sub)
End Sub
Public sub ParsePDF(byval intType as integer)
If textboxSource.text <>"" then
io.file.copy(textboxSource.text,textboxDestination.text,1)
'.... others operations....
End If
End Sub
...when code encounter textboxType.text or textboxSource.text and textboxDestination.text go on error because it say this object is from another thread...
How could i solve this problem ? My sub ParsePDF() have many reference to object in the form for extraction of values and count a big number of lines code... is there a way for bypass this issue ?
you can use threads :
simple example to execute sub in separate thread :
Imports System.Threading
{......}
Private Sub Button1_Click(sender As Object, e As EventArgs)
Dim BackProcess = New Thread(Sub() Me.analysePdf("d:\pdfFolder", 1))
BackProcess.Priority = ThreadPriority.Normal
BackProcess.Start()
end Sub
sub analysePdf(pdfPath as string, analyseType as integer)
'your stuff.............
'.......................
'send data to UI with invoke :
Me.BeginInvoke(Sub() textbox1.Text = "running...")
'etc...
end sub
I am using a Windows form application due to added security measures i have to work around for session in my application.Currently i am using a Timer to achieve the functionality I am able to close the form but i need to again restart the application to return to the login form.I am using the below code
Private Sub sessionTimer_Tick(sender As Object, e As EventArgs) Handles sessionTimer.Tick
Try
Me.sessionTimer.Stop()
Me.sessionTimer.Enabled = False
Process.Start(Application.StartupPath + "\application.exe")
Process.GetCurrentProcess().Kill()
Catch ex As Exception
End Try
End Sub
I am getting an exception when i use the above method and it doesn't serve the purpose,also i have already tried using Application.Restart didn't work out.Please help i am new to windows form. Also adding to this in order to reset the timer i am using the below code.
Private Sub frmMain_MouseMove(sender As Object, e As MouseEventArgs) Handles MyBase.MouseMove
Me.sessionTimer.Stop()
Me.sessionTimer.Start()
End Sub
But this doesn't seem to work the main form has menu's which i am using to navigate to other forms so the idle time should not include the time spent in other forms which are opened via the menu's. What event should i use in frmMain to handle this problem.Thanks
Just let the Framework do the work.
Application.Restart()
If your session Timer fires from a background thread (maybe you use System.Timers.Timer instead of System.Windows.Forms.Timer) you propable have to sync with your main thread.
Me.Invoke(new MethodInvoker(Addressof Application.Restart))
If Application.Restart does not work there is propably something wrong with your app. You should try the following.
If you created threads, be sure they are created with "thread.IsBackground = true" otherwise they will keep your process open
Stop your timers and background workers.
Be sure you don't have forms that handle the FormClosing event and set e.Cancel = true. In that case you have to take e.CloseReason into account.
User Mark Hurd posted a great post about what happens during Application.Restart, have a look here
Iam using this code to restart my application. It works very well.
System.Diagnostics.Process.Start(Application.ExecutablePath) 'First start a new instance
Me.Close() 'Close the current application
If this doesnt work. I think there is no way around than using another application which restarts the Process. Here is a code example (second application)
Private Shared Sub RestartApp(pid As Integer, applicationName As String, arguments As String)
' Wait for the process to terminate
Dim process__1 As Process = Nothing
Try
process__1 = Process.GetProcessById(pid)
process__1.WaitForExit(1000)
' ArgumentException to indicate that the
' process doesn't exist?
Catch ex As ArgumentException
End Try
Process.Start(applicationName, arguments)
'Arguments?
End Sub
Source of the code
I have a small VB.Net project with link to sql using web service (SOAP).
I have to make sure that all forms are totally responsive no matter what, and it's working pretty well. My only problem is on loading the application!
The main start-up form has only single line of code:
Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Await objWebService.GetCurrentSessionsAsync
End Sub
But while this "awaitable" code is being executed the form is unresponsive, frozen and wait cursor is displayed.
Any idea on what might be causing this issue and how to handle it?
In regard to your answer, the code can be much cleaner if you don't combine different programming patterns, check this out:
Private Async Sub frmMain_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Dim res = Await GetCurrentSessionsAsync()
End Sub
Private Async Function GetCurrentSessionsAsync() As Task(Of com.services.Server)
Try
Return Await Task.Factory.
StartNew(Function() objWebService.GetCurrentSessions)
Catch ex As Exception
Glob.ErrorLog("GetCurrentSessions", ex, True)
Return New com.services.Server
End Try
End Function
References:
try-catch (C# Reference)
Async Return Types (C# and Visual Basic)
The key problem is that Async does not magically make your method asynchronous. It only lets compiler know that your method will have Await keywords, and that the code needs to be converted into a state machine. Any code that is not awaited is executed synchronously, even if the method is marked as Async. Consider the following example:
Private Async Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Await LongRunning1() 'opens the form, then asynchronously changes
'Text property after 2 seconds
End Sub
Private Async Function LongRunning1() As Task
Await Task.Factory.StartNew(Sub() Threading.Thread.Sleep(2000))
Me.Text = "Finished LongRunning1"
End Function
Here a long running process, Thread.Sleep as an example, is wrapped into a Task, and there is an Await keyword. It tells the compiler to wait for the statements inside the task to finish, before executing the next line. Without the Await, the Text property would be set immediately.
Now suppose you have some long running synchronous code in your Async method:
Private Async Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Await LongRunning2() 'synchronously waits 2 seconds, opens the form,
'then asynchronously changes Text property after 2 seconds
End Sub
Private Async Function LongRunning2() As Task
Threading.Thread.Sleep(2000)
Await LongRunning1()
Me.Text = "Finished LongRunning2"
End Function
Notice in this case it synchronously waits for the Thread.Sleep to finish, so for the end user you app appears as hanging. Bottom line is - you have to know which method calls can be long running, and wrap them into a task based await model. Otherwise you may be seeing the problem you are seeing.
If this sounds too complicated, you can fire up a background worker (.NET 2.0+), or use TPL (.NET 4.0+) to start a task. If you wish to go into lower level, threading is available since .NET 1.1. Then display some wait/progress window/overlay on top of the form/control, for which the functionality is not yet available. Check these out:
Loading data from DB asynchronously in win forms
Await async with event handler
Thanks to #PanagiotisKanavos for pointing me in the right direction.
So here what it is (I have to say that the answer of Neolisk and Panagiotis led me to the solution):
What made my loading form unresponsive is what appeared to be a bug in web services, only the first call of my web service would produce this issue. So If the first call was made after form load, on another event, I would face same problem.
To fix this, I changed the way I call my first method through web service using TaskCompletionSource variable, and calling my first method using Thread. I'll post my before/after code to be sure I delivered my fix clearly.
Before:
Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim res = Await objWebService.GetCurrentSessionsAsync
End Sub
After:
Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim res = Await GetCurrentSessionsAsync()
End Sub
Dim _tcServer As New TaskCompletionSource(Of MyProject.com.services.Server)
Private Async Function GetCurrentSessionsAsync() As Task(Of com.services.Server)
Try
Dim th As New System.Threading.Thread(AddressOf GetCurrentSessions)
th.Start()
Return Await _tcServer.Task
Catch ex As Exception
Return New MyProject.com.services.Server
End Try
End Function
Private Sub GetCurrentSessions()
Try
Dim res = objWebService.GetCurrentSessions
_tcServer.SetResult(res)
Catch ex As Exception
Glob.ErrorLog("GetCurrentSessions", ex, True)
End Try
End Sub
I hope this can help others in the future.
Thank you.
I am currently studying VB.NET and I got question about using thread to open the form.
For example, when I click open button, then tread will start and open another form to adding or changing data.
Therefore, I tried to implement this part such as
Private Sub menu_Click(sender As Object, e As EventArgs) Handles menu.Click
Dim A As System.Threading.Thread = New Threading.Thread(AddressOf Task_A)
A.Start()
End Sub
Public Sub Task_A()
frmBuild.Show()
End Sub
However, I am getting error to open the frmBuild by thread. Do I need to use other method to open form?
And, How can we kill the thread when fromBuild closes?
This is almost always a bad idea. You shouldn't try to use a separate thread to open a Form - instead, open all of your forms on the main UI thread, and move the "work" that would otherwise block onto background threads. BackgroundWorker is a common means of handling the work.
That being said, if you need to do this for some unusual reason, you need to do two other things.
First, you need to set the apartment state of that thread. You also need to use Application.Run to display the form, and that form must be created on the proper thread:
Private Sub menu_Click(sender As Object, e As EventArgs) Handles menu.Click
Dim th As System.Threading.Thread = New Threading.Thread(AddressOf Task_A)
th.SetApartmentState(ApartmentState.STA);
th.Start()
End Sub
Public Sub Task_A()
frmBuild = New YourForm() ' Must be created on this thread!
Application.Run(frmBuild)
End Sub
In order to close the Form from the other thread, you can use:
frmBuild.BeginInvoke(New Action(Sub() frmBuild.Close()))
And, How can we kill the thread when fromBuild closes ?
The thread will automatically shut down when the form is closed, if it's written as shown above.
I am having the worst trouble getting around a bug, and am hoping that I can get some advice on this site. In short, I am trying to make an asynchronous web service call from my VB.NET application. But my "client_DownloadDataCompleted" callback is NEVER being called when the download is complete.
Here is my complete code:
Public Sub BeginAsyncDownload(ByVal Url As String)
Dim waiter As System.Threading.AutoResetEvent = New System.Threading.AutoResetEvent(False)
Dim client As WebClient = New WebClient()
'client_DownloadDataCompleted method gets called when the download completes.
AddHandler client.DownloadDataCompleted, AddressOf client_DownloadDataCompleted
Dim uri As Uri = New Uri(Url)
Downloading = True 'Class variable defined elsewhere
client.DownloadDataAsync(uri, waiter)
End Sub
Private Sub client_DownloadDataCompleted(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)
MessageBox.Show("Download Completed")
Downloading = False
Debug.Print("Downloaded")
End Sub
Again, the client_DownloadDataCompleted method is never being called. I have also tried using the method:
Private Sub client_DownloadDataCompleted(ByVal sender As Object, ByVal e As DownloadDataCompletedEventArgs)
With no luck. What I really need is that "Downloading" variable to be switched off when the download is complete.
Thanks in advance!
Brett
The client (Webclient) should be declared outside the BeginAsyncDownload subroutine, so it has a form/class level visibility. Please refer to the following code:
Public Class Form1
Dim client as New WebClient()
Private Sub BeginAsyncDownload(ByVal Url As String)
AddHandler client.DownloadDataCompleted, AddressOf client_DownloadDataCompleted
Dim uri As Uri = New Uri(Url)
Downloading = True 'Class variable defined elsewhere
client.DownloadDataAsync(uri, waiter)
End Sub
Private Sub client_DownloadStringCompleted(ByVal sender As Object, ByVal e As System.Net.DownloadStringCompletedEventArgs)
MessageBox.Show("Download Completed")
Downloading = False
Debug.Print("Downloaded")
End Sub
This is a tough one. I spent a little time on this and wasn't able to figure out why it wasn't getting called, sorry.
If you aren't able to get this to work, I have some code on CodePlex that includes a WebHelper class that might help you. I tried to make it as easy to use as WebClient but with all the power of HttpWebRequest.
The project is called BizArk. I wrote it just as a repository of code for myself. Feel free to just use the bits you want, I don't have any particular interest in how the code is used (as long as it's not used for evil :).
In what context are you invoking the webclient? WebClient will pick up your SynchronizationContext.Current and post its completion callback to it.
If you are using WinForms and your UI thread is blocked it will never be able to process your callback.