VB.NET DownloadDataAsync: - vb.net

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.

Related

VB.net Asynchronous call to Url with no response needed

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&parameter2=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

How to post a custom header with WebClient.UploadFileAsync in VB.Net

I have in my code, a file upload script that needs to post a authentication key header along with the upload. However, it doesn't seem to work like I expected. This is my code so far:
Private Sub uploadFile()
Dim address As String = "http://localhost/stripe/upload.php"
Dim client As WebClient = New WebClient()
Dim uri As Uri = New Uri(address)
AddHandler client.UploadFileCompleted, AddressOf UploadFileCompleted
AddHandler client.UploadProgressChanged, AddressOf UploadProgressCallback
client.Headers.Set("authKey", login.authKey)
client.UploadFileAsync(uri, "POST", uploadFileName)
End Sub
Private Sub UploadProgressCallback(ByVal sender As Object, ByVal e As UploadProgressChangedEventArgs)
ProgressBar1.Value = e.ProgressPercentage
Label3.Text = String.Format("{0} / {1} kB", Math.Round(e.BytesSent / 1024), Math.Round(e.TotalBytesToSend / 1024))
Label2.Text = String.Format("{0}%", e.ProgressPercentage)
Application.DoEvents()
End Sub
Private Sub UploadFileCompleted(ByVal sender As Object, ByVal e As UploadFileCompletedEventArgs)
Dim response As String = System.Text.Encoding.ASCII.GetString(e.Result)
Console.WriteLine(response)
End Sub
When I run this piece of code: Nothing happens. There is no line breaks in the output console or anything. Like the code never reached the UploadFileCompleted Sub. It doesn't seem to reach the UploadProgressCallback either, since the progress bar and the associated labels never update.
When I try to comment out the client.Headers.Set("authKey", login.authKey) line: The file seems to upload, but upon completion: I get a 403 Forbidden message as expected because I didn't have the authKey header set.
What am I doing wrong here?
I found my problem. The problem was caused by login.authKey being inaccessible to the thread it was called from. Since the program is multi-threaded: I had to make sure it was accessible to the thread. When I made it accessible: The function worked as expected.
Hope this helps other people behind me. :)

FileSystemWatcher - Cannot do this without API?

I want to check out if several folders are receieving new files and then handle that. This works fine, I have declared the FileSystemWatcher and set the EventHandler.
Now, everything works fine and if I create a new file there, it notices it.
Then, I noticed that when I paste a file, it does not notice it. I have already searched on Google and I read that it is not possible with the built-in FileSystemWatcher so far.
So I thought about API to manage this, but I have actually no idea how to deal with that or where to start. This program is one for a job, so I really need that.
I appreciate any help, links or something else to deal with that.
Thanks! if something is not clear, avoid a Downvote and ask me ;)
The following works completed as expected (.net v4.5). A paste into the directory fires the Change event.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim fw As New FileSystemWatcher
fw.Path = "c:\Temp"
fw.Filter = "*.*"
fw.IncludeSubdirectories = False
AddHandler fw.Created, New FileSystemEventHandler(AddressOf FileWatcherFileChange)
AddHandler fw.Deleted, New FileSystemEventHandler(AddressOf FileWatcherFileDeleted)
AddHandler fw.Renamed, New RenamedEventHandler(AddressOf FileWatcherFileRenamed)
AddHandler fw.Error, New ErrorEventHandler(AddressOf FileWatcherError)
fw.EnableRaisingEvents = True
End Sub
Private Sub FileWatcherFileChange(ByVal source As Object, ByVal e As FileSystemEventArgs)
MsgBox("Change")
End Sub
Private Sub FileWatcherFileDeleted(ByVal source As Object, ByVal e As FileSystemEventArgs)
MsgBox("Deleted")
End Sub
Private Sub FileWatcherFileRenamed(ByVal source As Object, ByVal e As FileSystemEventArgs)
MsgBox("Renamed")
End Sub
Private Sub FileWatcherError(ByVal source As Object, ByVal e As System.IO.ErrorEventArgs)
MsgBox("Error")
End Sub
End Class
There were so many comments, I want to ensure you read this so I post as an answer. Please read this answer from me in another thread in full, including what is written on CodeProject. If what you are delivering is important work code you should really take the time to read it all.
This FileSystemWatcher class features many surprises. It is a leaky abstraction - it doesn't work in any way like it should. It might work for a while, but it always fails when conditions change.
If I were you I would ditch the FileSystemWatcher class entirely and work with time and date based scans for new files. There may be other classes and pre-made components that can help you with this.
UPDATE: New information: https://stackoverflow.com/a/23704476/129130

Cross Thread invoke from class ? Confused - vb.net

maybe I am being stooped... but the fact is that I am a bit of a n00b concerning threading...
I am making use of a serial port in a class. I am raising an event from that class to my form calling the class. Event contains data received...
I wish to simply populate a textbox from the raised event.
Now I am not specifically creating a seperate thread, but I get the normal crossthreading error when trying to update my textbox on the UI, so my assumption is that the serial port and its internal methods probably creates its own threads...
Regardless, I am a bit confused as to how to properly implement an invoke, from my main form, pointing to the thread in the instantiated class...
I hope this makes sense...
Dim WithEvents tmpRS232 As New clsRS232
Private Sub but_txt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles but_txt.Click
tmpRS232.Set_com_port("COM8", 38400)
tmpRS232.Transmit_data(txt_tx.Text)
End Sub
Private Sub tmprs232_rx_data_returned(ByVal str_data As String) Handles tmpRS232.rx_data_returned
txt_rx.Text = str_data 'Cross threading error
MsgBox(str_data) 'Fires without errors
End Sub
Can someone please provide a code example based on this code?
thanks.
You are correct, the issue here is that you are attempting to update a UI element from a non-UI thread (in this case the serial port handler). What you need to do is check if the InvokeRequired flag is set on the control that you are trying to access from the callback. If so that means that you need to marshall your call to the UI thread. You can achieve this by using either Invoke or BeginInvoke from System.Windows.Forms.Control.
Private Delegate Sub SetRxTextCallback(ByVal [text] As String)
Private Sub SetRxText(ByVal [text] As String)
txt_rx.Text = [text]
End Sub
Private Sub tmprs232_rx_data_returned(ByVal str_data As String) Handles tmpRS232.rx_data_returned
If (txt_rx.InvokeRequired) Then
Dim d As New SetRxTextCallback(AddressOf Me.SetRxText)
Me.BeginInvoke(d, New Object() {[str_data]})
End If
'txt_rx.Text = str_data 'Cross threading error
'MsgBox(str_data) 'Fires without errors
End Sub
Here's a link to the MSDN documentation that explains it in detail.
Or simply...
Private Sub tmprs232_rx_data_returned(ByVal str_data As String) Handles tmpRS232.rx_data_returned
If InvokeRequired Then
Invoke(Sub()txt_rx.Text = str_data)
Else
txt_rx.Text = str_data
End If
End Sub

Why won't event change image?

I have been working very hard on figuring this out and just can't understand the events. Can someone help me understand the event process in my code? Or tell me why my image won't switch when it runs the code?
Declarations of Class and members
Partial Public Class Name
Implements IChat
Private member As String
Private instanceContext As InstanceContext
Private participant As IChatChannel
Private ostat As IOnlineStatus
Private factory As DuplexChannelFactory(Of IChatChannel)
Inside my Connect Sub
'Construct InstanceContext to handle messages on callback interface.
' An instance of ChatApp is created and passed to the InstanceContext.
instanceContext = New InstanceContext(Me)
' Create the participant with the given endpoint configuration
' Each participant opens a duplex channel to the mesh
' participant is an instance of the chat application that has opened a channel to the mesh
factory = New DuplexChannelFactory(Of IChatChannel)(instanceContext, "ChatEndpoint")
participant = factory.CreateChannel()
' Retrieve the PeerNode associated with the participant and register for online/offline events
' PeerNode represents a node in the mesh. Mesh is the named collection of connected nodes.
ostat = participant.GetProperty(Of IOnlineStatus)()
AddHandler ostat.Online, AddressOf Me.OnOnline
AddHandler ostat.Offline, AddressOf Me.OnOffline
Sub routines that are supposed to change image
Public Sub Join(ByVal member As String) Implements IChat.Join
instanceShellProp.imgP2P.Image = Namespace.My.Resources.Offline
MsgBox("JOINED OFFLINE")
End Sub
Public Sub Leave1(ByVal member As String) Implements IChat.Leave
instanceShellProp.imgP2P.Image = Namespace.My.Resources.Disconnected
MsgBox("NOT CONNECTED")
End Sub
Public Sub OnOnline(ByVal sender As Object, ByVal e As EventArgs)
instanceShellProp.imgP2P.Image = Namespace.My.Resources.Online
MsgBox("JOINED ONLINE")
End Sub
Public Sub OnOffline(ByVal sender As Object, ByVal e As EventArgs)
instanceShellProp.imgP2P.Image = Namespace.My.Resources.Offline
MsgBox("JOINED OFFLINE")
End Sub
instanceShellProp returns the instance of the Shell that is a MDI container.
All of the images are in the Resources and properly spelled and referenced to. The MessageBox will pop up but the images won't change, EXCEPT on Join.
I'm not trying to Code Dump, just trying to make sure that you can see what I am looking at and allow you to give better advice.
All help is appreciated!
EDIT
Okay, I find this weird... I feel like I am getting close. When the messagebox is not commented out the image will change, when it is commented out the image doesn't change.
Any better suggestions on how to get this to work?
Public Sub OnOnline(ByVal sender As Object, ByVal e As EventArgs)
With instanceShellProp.imgP2P
.Image = Nothing
.Visible = True
End With
'MsgBox("JOINED ONLINE")
With instanceShellProp.imgP2P
.Image = Namespace.My.Resources.Online
.Visible = True
End With
End Sub
Added Application.DoEvents() and it allowed it to work. Not sure as to why but if someone could explain that would be awesome! Thanks!
Try to call instanceShellProp.imgP2P.Refresh() after changing the image.
The documentation of Microsoft for Refresh says:
"Forces the control to invalidate its client area and immediately redraw itself and any child controls."