async/await on many forms ping function - vb.net

I have some problem and couldn't see so far what i am doing wrong. My application user can open some form multiple times and within each of it i want to make ping time to time to some remote host then show status on status bar, therefore to not block main thread and ui i decided to go asyn/await. Unfortunetly within 'DoWork' method 'StartNew' is highlited within this line:
Await Task.Factory.StartNew(IsDestinationReachable(IPAddress))
Severity Code Description Project File Line Suppression State
Error BC36645 Data type(s) of the type parameter(s) in method 'Public
Overloads Function StartNew(Of TResult)([function] As Func(Of
TResult)) As Task(Of TResult)' cannot be inferred from these
arguments. Specifying the data type(s) explicitly might correct this
error.
And by the way is it right way i am doing it? Check my code below:
Public Class FrmDrukujEtykiete
Private Property IPAddress As String
Private WithEvents mytimer As Timer
Sub New(ipaddress As String)
InitializeComponent()
AddHandler mytimer.Tick, AddressOf dowork
mytimer.Interval = 6000
mytimer.Enabled = True
mytimer.Start()
Me.IPAddress = ipaddress
End Sub
Public Async Sub dowork(sender As Object, e As EventArgs)
Dim MMOO As Task(Of Boolean) = Await Task.Factory.StartNew(IsDestinationReachable(IPAddress))
If MMOO.Result Then
tsPingResultIcon.BackColor = Color.Green
tsPingResultIcon.Text = "OK - Remote ip reachable"
Else
tsPingResultIcon.BackColor = Color.Red
tsPingResultIcon.Text = "NOT OK - Remote ip NOT reachable"
End If
End Sub
Public Function IsDestinationReachable(ByVal hostnameOrAddress As String) As Boolean
Dim reachable As Boolean = False
Try
reachable = My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(hostnameOrAddress)
Catch pingException As System.Net.NetworkInformation.PingException
Catch genericNetworkException As System.Net.NetworkInformation.NetworkInformationException
' Fail silently and return false
End Try
Return reachable
End Function
End Class
EDIT:
i think i was able to make it happen - one thing which still considering me is why when user opening new form before it show up its about 4 seconds... second thing is it correct - i mean can you check my code is there any wrong task conception usage? Generally working...
Public Class FrmDrukujEtykiete
Private etykieta As New Etykieta
Private Property IPAddress As String
Private WithEvents mytimer As New Timer
Sub New(ipaddress As String)
InitializeComponent()
Me.IPAddress = ipaddress
AddHandler mytimer.Tick, AddressOf dowork
mytimer.Interval = 6000
mytimer.Enabled = True
mytimer.Start()
DoSomethingElse()
End Sub
Private Sub DoSomethingElse()
For i = 1 To 100000
' Threading.Thread.Sleep(1000)
ListBox1.Items.Add(i)
Next
End Sub
Private Sub btnWyjdz_Click(sender As Object, e As EventArgs) Handles btnWyjdz.Click
Close()
End Sub
Public Async Sub dowork(sender As Object, e As EventArgs)
Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
'--Run lenghty task
Dim reachable = False
Try
reachable = My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(IPAddress)
Catch pingException As System.Net.NetworkInformation.PingException
Catch genericNetworkException As System.Net.NetworkInformation.NetworkInformationException
' Fail silently and return false
End Try
Return reachable
End Function)
Await tsk
ListBox2.Items.Add("a teraz zmiana")
If tsk.Result Then
tsPingResultIcon.BackColor = Color.Green
tsPingResultIcon.Text = "OK - Remote ip reachable"
Else
tsPingResultIcon.BackColor = Color.Red
tsPingResultIcon.Text = "NOT OK - Remote ip NOT reachable"
End If
End Sub
Public Function IsDestinationReachable(ByVal hostnameOrAddress As String)
Dim reachable = False
Try
reachable = My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(hostnameOrAddress)
Catch pingException As System.Net.NetworkInformation.PingException
Catch genericNetworkException As System.Net.NetworkInformation.NetworkInformationException
' Fail silently and return false
End Try
Return reachable
End Function
End Class

Your updated code is not typically how you would use Async/Await. More usual would be something like:
Public Async Sub dowork(sender As Object, e As EventArgs)
Dim isReachable As Boolean = Await Task.Factory.StartNew(Function() IsDestinationReachable(IPAddress))
If isReachable Then
tsPingResultIcon.BackColor = Color.Green
tsPingResultIcon.Text = "OK - Remote ip reachable"
Else
tsPingResultIcon.BackColor = Color.Red
tsPingResultIcon.Text = "NOT OK - Remote ip NOT reachable"
End If
End Sub
The Await suspends the method until the task completes and then returns the result of the task, so there is no need to hold onto the Task object and use .Result. While the method is suspended, execution of the non-Awaiting code continues on the main thread, and the method is resumed on the main thread when the async method completes.
However, since network IO is naturally async, you would be better off using the Ping.SendPingAsync method instead of Task.Factory.StartNew. That would be something like this (untested code):
Public Async Sub dowork(sender As Object, e As EventArgs)
Dim isReachable As Boolean = Await IsDestinationReachable(IPAddress)
If isReachable Then
tsPingResultIcon.BackColor = Color.Green
tsPingResultIcon.Text = "OK - Remote ip reachable"
Else
tsPingResultIcon.BackColor = Color.Red
tsPingResultIcon.Text = "NOT OK - Remote ip NOT reachable"
End If
End Sub
Public Async Function IsDestinationReachable(ByVal hostnameOrAddress As String) As Boolean
Dim reachable As Boolean = False
Try
If My.Computer.Network.IsAvailable Then
Dim pinger As Ping = New Ping()
Dim result As PingReply = Await pinger.SendPingAsync(hostnameOrAddress)
reachable = result.Status = IPStatus.Success
End If
Catch pingException As System.Net.NetworkInformation.PingException
Catch genericNetworkException As System.Net.NetworkInformation.NetworkInformationException
' Fail silently and return false
End Try
Return reachable
End Function

Related

System.Diagnostics.Process not properly closing after the application is closed

I have been trying to find a solution to why the ExitTool I am using is not properly closing out after I close the main application. What is happening is that when I close my application, the ExifTool stays running in the background and I have to manually kill it.
Here is the code snippet of the process startup.
Public Shared Sub ExecuteExifTool()
If ExifToolStarted Then Exit Sub
ExifToolStarted = True
Dim NowString As String = Date.Now.ToString("yyyyMMddHHmmss")
If Not IO.Directory.Exists(".\Runtime") Then IO.Directory.CreateDirectory(".\Runtime")
Dim GetDirectory As New IO.DirectoryInfo(".\Runtime")
If GetDirectory.GetFiles.Count > 0 Then
For Each i As IO.FileInfo In GetDirectory.GetFiles
If i.FullName.Contains("exif.Yv") AndAlso i.FullName.Contains("-cL") AndAlso i.FullName.Contains(".exe") Then : Try : i.Delete() : Catch : End Try : End If
Next
End If
HostName = ".\Runtime\exif.Yv" & NowString.Substring(0, 8) & "-cL" & NowString.Substring(8, 6) & ".exe"
IO.File.Copy(".\exiftool.exe", HostName)
Using ExifToolProcess As New Process
With ExifToolProcess
.StartInfo.RedirectStandardInput = True
.StartInfo.FileName = HostName
.StartInfo.UseShellExecute = False
.StartInfo.Arguments = "-stay_open" & " True -# " & "-"
.StartInfo.RedirectStandardOutput = True
.StartInfo.RedirectStandardError = True
.StartInfo.CreateNoWindow = True
.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
.Start()
.BeginOutputReadLine()
.BeginErrorReadLine()
End With
End Using
End Sub
The latest attempt to solve this issue was to try and launch another executable application; which essentially, is another Windows.Forms.Form that waits for the main application to close and then it will attempt to kill the process immediately afterwards, then dispose of itself. Here is the snippet.
Public Class KillProcess
Private _ProcessName As String
Public Property ProcessName As String
Get
Return _ProcessName
End Get
Set(value As String)
_ProcessName = value
End Set
End Property
Private _MainApp As Form
Public Property MainApplication As Form
Get
Return _MainApp
End Get
Set(value As Form)
_MainApp = value
End Set
End Property
Private Sub KillProcess_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CleanupProcess()
End Sub
Public Sub CleanupProcess()
While Not MainApplication.IsDisposed
Dim FilesToDelete As New List(Of String)
Dim ProcessesToKill As New List(Of Process)
For Each p As Process In Process.GetProcesses
If p.ProcessName = ProcessName Then
FilesToDelete.Add(p.MainModule.FileName)
ProcessesToKill.Add(p)
End If
Next
For Each p As Process In ProcessesToKill
Try
p.Kill()
p.WaitForExit(10000)
p.Close()
Catch winException As System.ComponentModel.Win32Exception
Catch invalidException As InvalidOperationException
End Try
Next
End While
Me.Dispose()
End Sub
End Class
And here is the code snippet of the startup.
Public Sub CleanupTask()
Dim Handler As New Custodian.KillProcess With {.ProcessName = ExifToolHooker.HostName, .MainApplication = Me}
Windows.Forms.Application.Run(Handler)
End Sub
Private Sub CloseApplication(sender As Object, e As FormClosingEventArgs) Handles Me.Closing
Dim TaskHandler As Thread = New Thread(AddressOf CleanupTask)
TaskHandler.SetApartmentState(ApartmentState.STA)
TaskHandler.Start()
...
End Sub

Get File Size on FTP Server and put it on a Label

I'm trying to get the size of a file that is hosted on a FTP Server and put it in a Label while the `BackgroundWorker works in the background.
I'm using "Try" to get the value, however the value is caught on the first attempt. After downloading, if I press to try to get it again then it works.
Note: The progress bar also does not work on the first try.
Image
What I have tried:
Private Sub BWorkerD_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BWorkerD.DoWork
Dim buffer(1023) As Byte
Dim bytesIn As Integer
Dim totalBytesIn As Integer
Dim output As IO.Stream
Dim flLength As Integer
''TRY TO GET FILE SIZE''
Try
Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePathD.Text), FtpWebRequest)
FTPRequest.Credentials = New NetworkCredential(txtFTPUsernameD.Text, txtFTPPasswordD.Text)
FTPRequest.Method = Net.WebRequestMethods.Ftp.GetFileSize
flLength = CInt(FTPRequest.GetResponse.ContentLength)
lblFileSizeD.Text = flLength & " bytes"
Catch ex As Exception
End Try
Try
Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePathD.Text), FtpWebRequest)
FTPRequest.Credentials = New NetworkCredential(txtFTPUsernameD.Text, txtFTPPasswordD.Text)
FTPRequest.Method = WebRequestMethods.Ftp.DownloadFile
Dim stream As IO.Stream = FTPRequest.GetResponse.GetResponseStream
Dim OutputFilePath As String = txtSavePathD.Text & "\" & IO.Path.GetFileName(txtFilePathD.Text)
output = IO.File.Create(OutputFilePath)
bytesIn = 1
Do Until bytesIn < 1
bytesIn = stream.Read(buffer, 0, 1024)
If bytesIn > 0 Then
output.Write(buffer, 0, bytesIn)
totalBytesIn += bytesIn
lblDownloadedBytesD.Text = totalBytesIn.ToString & " bytes"
If flLength > 0 Then
Dim perc As Integer = (totalBytesIn / flLength) * 100
BWorkerD.ReportProgress(perc)
End If
End If
Loop
output.Close()
stream.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
''UPDATE EVERY PROGRESS - DONT WORK ON FIRST TRY''
Private Sub BWorkerD_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BWorkerD.ProgressChanged
pBarD.Value = e.ProgressPercentage
lblPercentD.Text = e.ProgressPercentage & " %"
End Sub
The main problems (set Option Strict On to find more):
You can't access the UI objects from a thread different than the UI Thread.
The error you receive is:
Cross-thread operation not valid:Control lblFileSizeD accessed from
a thread other than the thread it was created on
Then, the same error for lblDownloadedBytesD.
Also, you are eating up your Error messages using an empty handler with:
Catch ex As Exception
End Try
This nullifies any handling, because there's none. You are simply letting the code run past it without taking any action. The handlers are there to, well, handle the errors, not to let them go unchecked.
When you need to access and update some UI component property, use the BackGroundWorker ReportProgress() method. This method has an overload that accepts a parameter of type Object. Meaning, you can feed it anything. This Object will be the e.UserState property in the ReportProgress ProgressChangedEventArgs class.
The .RunWorkerAsync() method also accepts an Object parameter. This Object will become the e.Argument property of the BackgroundWorker.DoWork Event. This gives some flexibility in relation to the parameters you can actually pass to your BackGroundWorker.
One more problem: the Ftp Download procedure does not support cancellation. When run, a user can't stop it.
Last problem: as reported in the documentation, you should never reference the BackGroundWorker object you instantiated in your UI thread (the Form) in its DoWork event. Use the sender object and cast it to the BackGroundWorker class.
In this example, all the UI references are delegated to a Class object that is passed to the DoWork event through the RunWorkerAsync(Object) method (using the e.Argument property).
The Class object is updated with progress details and then fed to the ReportProgress(Int32, Object) method, which runs in the original Synchronization Context (the UI thread, where the RunWorkerAsync method is called).
The UI can be updated safely. No cross-thread operations can occur.
A cancellation method is also implemented. This allows to abort the download procedure and to delete a partial downloaded file, if one is created.
The error handling is minimal, but this is something you need to integrate with your own tools.
(I've used the same names for the UI Controls, it should be easier to test.)
Imports System.ComponentModel
Imports System.Globalization
Imports System.IO
Imports System.Net
Imports System.Net.Security
Imports System.Security.Cryptography.X509Certificates
Public Class frmBGWorkerDownload
Friend WithEvents BWorkerD As BackgroundWorker
Public Sub New()
InitializeComponent()
BWorkerD = New BackgroundWorker()
BWorkerD.WorkerReportsProgress = True
BWorkerD.WorkerSupportsCancellation = True
AddHandler BWorkerD.DoWork, AddressOf BWorkerD_DoWork
AddHandler BWorkerD.ProgressChanged, AddressOf BWorkerD_ProgressChanged
AddHandler BWorkerD.RunWorkerCompleted, AddressOf BWorkerD_RunWorkerCompleted
BWorkerD.RunWorkerAsync(BGWorkerObj)
End Sub
Private Class BGWorkerObject
Public Property UserName As String
Public Property Password As String
Public Property ResourceURI As String
Public Property FilePath As String
Public Property FileLength As Long
Public Property DownloadedBytes As Long
Public Property BytesToDownload As Long
End Class
Private Sub btnDownload_Click(sender As Object, e As EventArgs) Handles btnDownload.Click
pBarD.Value = 0
Dim BGWorkerObj As BGWorkerObject = New BGWorkerObject With {
.ResourceURI = txtFilePathD.Text,
.FilePath = Path.Combine(txtSavePathD.Text, Path.GetFileName(txtFilePathD.Text)),
.UserName = txtFTPUsernameD.Text,
.Password = txtFTPPasswordD.Text
}
End Sub
Private Sub BWorkerD_DoWork(sender As Object, e As DoWorkEventArgs)
Dim BGW As BackgroundWorker = TryCast(sender, BackgroundWorker)
Dim BGWorkerObj As BGWorkerObject = TryCast(e.Argument, BGWorkerObject)
Dim FTPRequest As FtpWebRequest
Dim BufferSize As Integer = 131072
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
ServicePointManager.ServerCertificateValidationCallback =
Function(snd As Object, Cert As X509Certificate, Chain As X509Chain, Err As SslPolicyErrors)
Return True
End Function
FTPRequest = DirectCast(WebRequest.Create(BGWorkerObj.ResourceURI), FtpWebRequest)
FTPRequest.Credentials = New NetworkCredential(BGWorkerObj.UserName, BGWorkerObj.Password)
'FTPRequest.Method = WebRequestMethods.Ftp.GetFileSize
'----------------------- UPDATE ------------------------
FTPRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails
'--------------------- END UPDATE ------------------------
FTPRequest.EnableSsl = True
'----------------------- UPDATE ------------------------
Using FtpResponse As WebResponse = FTPRequest.GetResponse,
DirListStream As Stream = FtpResponse.GetResponseStream(),
listReader As StreamReader = New StreamReader(DirListStream)
While Not listReader.EndOfStream
Dim DirContent As String = listReader.ReadLine()
If DirContent.Contains(Path.GetFileNameWithoutExtension(BGWorkerObj.ResourceURI)) Then
BGWorkerObj.FileLength = Convert.ToInt64(DirContent.Split(New String() {" "}, StringSplitOptions.RemoveEmptyEntries)(4))
BGW.ReportProgress(0, BGWorkerObj)
Exit While
End If
End While
End Using
'----------------------- END UPDATE ------------------------
'Using FtpResponse As WebResponse = FTPRequest.GetResponse
' BGWorkerObj.FileLength = Convert.ToInt64(FtpResponse.ContentLength)
' BGW.ReportProgress(0, BGWorkerObj)
'End Using
If BGW.CancellationPending Then e.Cancel = True
Try
FTPRequest = CType(WebRequest.Create(BGWorkerObj.ResourceURI), FtpWebRequest)
FTPRequest.EnableSsl = True
FTPRequest.Credentials = New NetworkCredential(BGWorkerObj.UserName, BGWorkerObj.Password)
FTPRequest.Method = WebRequestMethods.Ftp.DownloadFile
Using Response As FtpWebResponse = DirectCast(FTPRequest.GetResponse, FtpWebResponse)
If Response.StatusCode > 299 Then
e.Result = 0
Throw New Exception("The Ftp Server rejected the request. StatusCode: " &
Response.StatusCode.ToString(),
New InvalidOperationException(Response.StatusCode.ToString()))
Exit Sub
End If
Using stream = Response.GetResponseStream(),
fileStream As FileStream = File.Create(BGWorkerObj.FilePath)
Dim read As Integer
Dim buffer As Byte() = New Byte(BufferSize - 1) {}
Do
read = stream.Read(buffer, 0, buffer.Length)
fileStream.Write(buffer, 0, read)
BGWorkerObj.DownloadedBytes += read
BGWorkerObj.BytesToDownload = BGWorkerObj.FileLength - BGWorkerObj.DownloadedBytes
If BGW.CancellationPending Then
e.Cancel = True
Exit Do
Else
BGW.ReportProgress(CInt((CSng(BGWorkerObj.DownloadedBytes) / BGWorkerObj.FileLength) * 100), BGWorkerObj)
End If
Loop While read > 0
End Using
End Using
Catch ex As Exception
If e.Cancel = False Then Throw
Finally
If e.Cancel = True Then
If File.Exists(BGWorkerObj.FilePath) Then
File.Delete(BGWorkerObj.FilePath)
End If
End If
End Try
End Sub
Private Sub BWorkerD_ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
pBarD.Value = e.ProgressPercentage
lblPercentD.Text = e.ProgressPercentage.ToString() & " %"
If lblFileSizeD.Text.Length = 0 Then
lblFileSizeD.Text = CType(e.UserState, BGWorkerObject).FileLength.ToString("N0", CultureInfo.CurrentUICulture.NumberFormat)
End If
lblDownloadedBytesD.Text = CType(e.UserState, BGWorkerObject).DownloadedBytes.ToString("N0", CultureInfo.CurrentUICulture.NumberFormat)
If e.ProgressPercentage <= 15 Then
lblDownloadedBytesD.ForeColor = Color.Red
ElseIf e.ProgressPercentage <= 66 Then
lblDownloadedBytesD.ForeColor = Color.Orange
Else
lblDownloadedBytesD.ForeColor = Color.LightGreen
End If
End Sub
Private Sub BWorkerD_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
Dim DownloadAborted As Boolean = False
If e.Error IsNot Nothing Then
DownloadAborted = True
lblDownloadedBytesD.ForeColor = Color.Red
lblDownloadedBytesD.Text = "Error!"
ElseIf e.Cancelled Then
DownloadAborted = True
lblDownloadedBytesD.ForeColor = Color.Yellow
lblDownloadedBytesD.Text = "Cancelled!"
pBarD.Value = 0
lblPercentD.Text = "0%"
Else
lblDownloadedBytesD.ForeColor = Color.LightGreen
lblDownloadedBytesD.Text = "Download completed"
End If
End Sub
Private Sub btnAbortDownload_Click(sender As Object, e As EventArgs) Handles btnAbortDownload.Click
BWorkerD.CancelAsync()
End Sub
End Class
A visual result of the operation described:
A PasteBin of the Form's Designer + Code

Fire method on Main Thread from other Threads

Issue
I am using multi-threading inside my application and the way it works is that i have an array that contains 22 string which stand for some file names:
Public ThreadList As String() = {"FSANO1P", "FJBJB1P", "COPOR1P", "FFBIVDP", "FFCHLDP", "FFDBKDP", "FFDREQP", "FFINVHP", "FFJMNEP", "FFPIVHP", "FFUNTTP", "FJBJM1P", "FJBJM2P", "FJBNT2P", "FPPBE9P", "FTPCP1P", "FTTEO1P", "FTTRQ1P", "FJBJU1P", "FTTEG1P", "FFJACPP", "XATXTDP"}
I then loop through the array and create a new thread for each file:
For Each mThreadName As String In ThreadList
Dim mFileImportThread = New FileImportThreadHandling(mThreadName, mImportGuid, mImportDate, Directory_Location, mCurrentProcessingDate, mRegion)
Next
So inside the new thread 'FileImportThreadHandling' it will call a method by starting a new thread:
mThread = New Thread(AddressOf DoWork)
mThread.Name = "FileImportThreadHandling"
mThread.Start()
Then in 'DoWork' it will determine what file is current in question and will run the code related to the file.
After the code has ran for the file I want to report this back to the main thread. Can somebody give me a solution please.
You will need to use Delegates
EDIT:
Take a look at this snippet:
Sub Main()
mThread = New Thread(AddressOf doWork)
mThread.Name = "FileImportThreadHandling"
mThread.Start()
End Sub
Sub doWork()
'do a lot of hard work
workDone(result)
End Sub
Delegate Sub workDoneDelegate(result As Integer)
Sub workDone(abilita As Boolean, Optional src As Control = Nothing)
If Me.InvokeRequired Then
Me.Invoke(New workDoneDelegate(AddressOf workDone), {result})
Else
'here you're on the main thread
End If
End Sub
Here is an example that might give you some ideas. Note the use of Async and Task. You will need a form with two buttons, and a label.
Public Class Form1
Public ThreadList As String() = {"FSANO1P", "FJBJB1P", "COPOR1P", "FFBIVDP", "*******", "FFJACPP", "XATXTDP"}
'note Async keyword on handler
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
Dim running As New List(Of Task)
For Each tskName As String In ThreadList
'start new task
Dim tsk As Task
tsk = Task.Run(Sub()
For x As Integer = 1 To 10
Dim ct As Integer = x
'simulate code related to the file
Threading.Thread.Sleep(500)
'report to the UI
Me.Invoke(Sub()
Label1.Text = String.Format("{0} {1}", tskName, ct)
End Sub)
Next
End Sub)
Threading.Thread.Sleep(100) 'for testing delay between each start
running.Add(tsk)
Next
'async wait for all to complete
For Each wtsk As Task In running
Await wtsk
Next
Button1.Enabled = True
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'test UI responsive during test
Label1.Text = DateTime.Now.ToString
End Sub
End Class
Using Actions and a callback to track remaining operations. (Simplified your class for my example)
Public ThreadList As String() = {"FSANO1P", "FJBJB1P", "COPOR1P", "FFBIVDP", "FFCHLDP"}
Private actionCounter As Integer = 0
Private lockActionCounter As New Object()
Sub Main()
Console.WriteLine("Starting...")
For Each mThreadName As String In ThreadList
Dim mFileImportThread = New FileImportThreadHandling(mThreadName)
actionCounter += 1
Call New Action(AddressOf mFileImportThread.DoWork).
BeginInvoke(AddressOf callback, mThreadName)
Next
Console.Read()
End Sub
Private Sub callback(name As IAsyncResult)
Dim remainingCount As Integer
SyncLock lockActionCounter
actionCounter -= 1
remainingCount = actionCounter
End SyncLock
Console.WriteLine("Finished {0}, {1} remaining", name.AsyncState, actionCounter)
If remainingCount = 0 Then Console.WriteLine("All done")
End Sub
Private Class FileImportThreadHandling
Shared r = New Random()
Private _name As String
Public Sub New(name As String)
_name = name
End Sub
Public Sub DoWork()
Dim delayTime = (r).Next(500, 5000)
Console.WriteLine("Doing {0} for {1:0}ms.", _name, delayTime)
Thread.Sleep(delayTime)
End Sub
End Class

I have a downladed file from ssh but it takes 50 seconds to complete the download

I am using vb.net to download a file and using Tamir.SharpSsh which works well except its slow it takes about 50 seconds to download a 3.5 kb file. My Question is How would I best put a wait function in for 2 mins to ensure the file is downloaded.
Public Function DownloadPricat() As Boolean
Dim retVal As Boolean
Dim PRICAT_CSV As String
Dim sfilename As String = ""
Dim ifilename As String
utils = New ThreeSoftware.Configuration.Utilities.utilConfigurationLoader("CONFIGURATION FILES\GEMINI RELATED\SkechersImport.ini")
Hostname = utils.GetIniSetting("SSH SECTION", "SSH_HOST", "")
username = utils.GetIniSetting("SSH SECTION", "SSH_USERNAME", "")
passsword = utils.GetIniSetting("SSH SECTION", "SSH_PASSWORD", "")
port = utils.GetIniSetting("SSH SECTION", "SSH_PORT", "")
HomeDirectoy = utils.GetIniSetting("SSH SECTION", "SSH_REMOTE_DIRECTORY", "")
transfer = New wcSFtp(Hostname, Integer.Parse(port), username, passsword)
PRICAT_CSV = utils.GetIniSetting("PATHS SECTION", "PRICAT_CSV", "")
sfilename = utils.GetIniSetting("PATHS SECTION", "PRICAT_FILENAME", "")
ifilename = PRICAT_CSV & "\" & sfilename
If transfer.getFile(HomeDirectoy & "Pricat.edi", ifilename) = True Then
MsgBox("Download Complete", vbInformation, "Import")
retVal = True
Else
retVal = False
End If
End Function
Get File is simply this
Public Function getFile(ByVal remotePath As String, ByVal localFile As String) As Boolean
Try
transfer = New Sftp(Me._hostname, Me._username, Me._password)
transfer.Connect(Me._port)
transfer.Get(remotePath, localFile)
transfer.Close()
Return True
Catch ex As Exception
Debug.Print("Error downloading file: " & ex.ToString)
Return False
End Try
End Function
Put the whole download into a backgroundworker's DoWork() function and add the Boolean result as the result-variable of the eventargs variable.
Then handle the RunWorkerCompleted() event of the backgroundworker and perform whatever task you want to happen after the download from there. That way you make sure the download is actually finished.
Public Class Form1
Private WithEvents LazyBGW As New System.ComponentModel.BackgroundWorker
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Initiate the backgroundworker. It runs in another thread.
LazyBGW.RunWorkerAsync()
End Sub
Private Sub LazyBGW_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles LazyBGW.DoWork
'This code runs in the BGW-Thread
'Perform the whole download task here or just call your
e.Result = DownloadPricat()
'Work is done, put results in the eventargs-variable for further processing
End Sub
Private Sub LazyBGW_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles LazyBGW.RunWorkerCompleted
'This code runs in the UI-Thread
Dim results As Boolean = CBool(e.Result)
MessageBox.Show("The worker is done and our result is: " & results.ToString)
End Sub
End Class
Edit:
In a console app you can use a Task:
Module Module1
Private Function DownloadPricat() As Boolean
Threading.Thread.Sleep(10000)
Return True
End Function
Sub Main()
Dim DLTask As New System.Threading.Tasks.Task(Of Boolean)(Function() DownloadPricat())
DLTask.Start()
Dim ThisTime As Date = Date.Now
Console.Write("Downloading")
While DLTask.IsCompleted = False AndAlso DLTask.IsCanceled = False AndAlso DLTask.IsFaulted = False
If (Date.Now - ThisTime).TotalSeconds > 1 Then
Console.Write(".")
ThisTime = Date.Now
End If
End While
Console.Write("Done.")
End Sub
End Module

Check Internet Connection vb.net

I am trying to run some vb.net code that indicates if i'm connected to the internet
If My.Computer.Network.IsAvailable Then
MsgBox("Computer is connected.")
Else
MsgBox("Computer is not connected.")
End If
This works fine if I'm connecting to a WiFi signal that doesn't require a login. If I connect to a public WiFi signal that I'm required to login/pay and I execute the code before completing this step it still tells me I'm connected (in theory yes but without paying/logging in I'm not)
Any ideas how set this up?
Thanks
You could check for an internet connection by trying to read Google.com:
Public Shared Function CheckForInternetConnection() As Boolean
Try
Using client = New WebClient()
Using stream = client.OpenRead("http://www.google.com")
Return True
End Using
End Using
Catch
Return False
End Try
End Function
Taken from: Here
I use this
Public Function HaveInternetConnection() As Boolean
Try
Return My.Computer.Network.Ping("www.google.com")
Catch
Return False
End Try
End Function
I create this class to track internet connection changes. This class can check the stable internet connections also (stable means, that the connection not change during N second). The class raise events, if the connection changes.
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Runtime.InteropServices.ComTypes
Imports System.Text
Imports System.Collections.Generic
Imports System.Linq
Imports System.Net.NetworkInformation
Imports System.Net
Public Enum InternetConnectionState
Connected
Disconnected
End Enum
Public Class NetworkConnections
Implements IDisposable
Public Shared Property CheckHostName As String = "www.google.com"
Public Property ConnectionStableAfterSec As Integer = 10
Private MonitoringStarted As Boolean = False
Private StableCheckTimer As System.Threading.Timer
Private IsFirstCheck As Boolean = True
Private wConnectionIsStable As Boolean
Private PrevInternetConnectionState As InternetConnectionState = InternetConnectionState.Disconnected
Public Event InternetConnectionStateChanged(ByVal ConnectionState As InternetConnectionState)
Public Event InternetConnectionStableChanged(ByVal IsStable As Boolean, ByVal ConnectionState As InternetConnectionState)
Public Sub StartMonitoring()
If MonitoringStarted = False Then
AddHandler NetworkChange.NetworkAddressChanged, AddressOf NetworkAddressChanged
MonitoringStarted = True
NetworkAddressChanged(Me, Nothing)
End If
End Sub
Public Sub StopMonitoring()
If MonitoringStarted = True Then
Try
RemoveHandler NetworkChange.NetworkAddressChanged, AddressOf NetworkAddressChanged
Catch ex As Exception
End Try
MonitoringStarted = False
End If
End Sub
Public ReadOnly Property ConnectionIsStableNow As Boolean
Get
Return wConnectionIsStable
End Get
End Property
<DllImport("wininet.dll")> _
Private Shared Function InternetGetConnectedState(ByRef Description As Integer, ByVal ReservedValue As Integer) As Boolean
End Function
Private Shared Function IsInternetAvailable() As Boolean
Try
Dim ConnDesc As Integer
Dim conn As Boolean = InternetGetConnectedState(ConnDesc, 0)
Return conn
Catch
Return False
End Try
End Function
Private Shared Function IsInternetAvailableByDns() As Boolean
Try
Dim iheObj As IPHostEntry = Dns.GetHostEntry(CheckHostName)
Return True
Catch
Return False
End Try
End Function
Public Shared Function CheckInternetConnectionIsAvailable() As Boolean
Return IsInternetAvailable() And IsInternetAvailableByDns()
End Function
Private Sub NetworkAddressChanged(sender As Object, e As EventArgs)
wConnectionIsStable = False
StableCheckTimer = New System.Threading.Timer(AddressOf ElapsedAndStable, Nothing, New TimeSpan(0, 0, ConnectionStableAfterSec), New TimeSpan(1, 0, 0))
If IsFirstCheck Then
If CheckInternetConnectionIsAvailable() Then
PrevInternetConnectionState = InternetConnectionState.Connected
RaiseEvent InternetConnectionStateChanged(InternetConnectionState.Connected)
Else
PrevInternetConnectionState = InternetConnectionState.Disconnected
RaiseEvent InternetConnectionStateChanged(InternetConnectionState.Disconnected)
End If
IsFirstCheck = False
Else
If CheckInternetConnectionIsAvailable() Then
If PrevInternetConnectionState <> InternetConnectionState.Connected Then
PrevInternetConnectionState = InternetConnectionState.Connected
RaiseEvent InternetConnectionStateChanged(InternetConnectionState.Connected)
End If
Else
If PrevInternetConnectionState <> InternetConnectionState.Disconnected Then
PrevInternetConnectionState = InternetConnectionState.Disconnected
RaiseEvent InternetConnectionStateChanged(InternetConnectionState.Disconnected)
End If
End If
End If
End Sub
Private Sub ElapsedAndStable()
If wConnectionIsStable = False Then
wConnectionIsStable = True
Dim hasnet As Boolean = CheckInternetConnectionIsAvailable()
RaiseEvent InternetConnectionStableChanged(True, IIf(hasnet, InternetConnectionState.Connected, InternetConnectionState.Disconnected))
End If
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
Try
RemoveHandler NetworkChange.NetworkAddressChanged, AddressOf NetworkAddressChanged
Catch ex As Exception
End Try
End If
' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
'Protected Overrides Sub Finalize()
' ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
' Dispose(False)
' MyBase.Finalize()
'End Sub
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
Track changes on a form with 2 listbox. Important! The events are thread unsafe, that need to be handle with invoke method.
Imports System.Net.NetworkInformation
Imports System.Net
Public Class frmNetworkConnections
Private WithEvents conn As NetworkConnections
Delegate Sub AddToList1Callback(ByVal ConnectionState As InternetConnectionState, ByVal IsStable As Boolean)
Delegate Sub AddToList2Callback(ByVal ConnectionState As InternetConnectionState, ByVal IsStable As Boolean)
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
conn = New NetworkConnections
End Sub
Sub AddToList1(ByVal ConnectionState As InternetConnectionState, ByVal IsStable As Boolean)
If Me.InvokeRequired = True Then
Dim d As New AddToList1Callback(AddressOf AddToList1)
Me.Invoke(d, ConnectionState, IsStable)
Else
ListBox1.Items.Add(Now & " - State: " & ConnectionState.ToString() & ", Stable: " & IsStable)
End If
End Sub
Sub AddToList2(ByVal ConnectionState As InternetConnectionState, ByVal IsStable As Boolean)
If Me.InvokeRequired = True Then
Dim d As New AddToList2Callback(AddressOf AddToList2)
Me.Invoke(d, ConnectionState, IsStable)
Else
ListBox1.Items.Add(Now & " - State: " & ConnectionState.ToString() & ", Stable: " & IsStable)
ListBox2.Items.Add(Now & " - State: " & ConnectionState.ToString() & ", Stable: " & IsStable)
End If
End Sub
Private Sub conn_InternetConnectionStableChanged(IsStable As Boolean, ConnectionState As InternetConnectionState) Handles conn.InternetConnectionStableChanged
AddToList2(ConnectionState, IsStable)
End Sub
Private Sub conn_InternetConnectionStateChanged(ConnectionState As InternetConnectionState) Handles conn.InternetConnectionStateChanged
AddToList1(ConnectionState, False)
End Sub
Private Sub btnStartMonitoring_Click(sender As Object, e As EventArgs) Handles btnStartMonitoring.Click
btnStopMonitoring.Enabled = True
btnStartMonitoring.Enabled = False
conn.StartMonitoring()
End Sub
Private Sub btnStopMonitoring_Click(sender As Object, e As EventArgs) Handles btnStopMonitoring.Click
btnStopMonitoring.Enabled = False
btnStartMonitoring.Enabled = True
conn.StopMonitoring()
End Sub
End Class
The result is:
I use the stable connection changes.
If you dont want to track changes, only check the connection, you can use the CheckInternetConnectionIsAvailable() shared function.
You could use the Ping class to try to reach a host in the Internet. In order not to wait too long, you should set a timeout when using Send.
A good way to check if the user is connected to the internet is
If My.Computer.Network.Ping("www.google.com") Then
MsgBox("Computer is connected to the internet.")
End If
You can also use this code, however it's slower
Public Shared Function CheckForInternetConnection() As Boolean
Try
Using client = New WebClient()
Using stream = client.OpenRead("http://www.google.com")
Return True
End Using
End Using
Catch
Return False
End Try
End Function
***** Best *****
The best Code For it, it not make any bug or Any slow.
Button Or Timer .. Etc
Try
If My.Computer.Network.Ping("www.google.com") Then
Label1.Text = "Internet Founded"
End If
Catch ex As Exception
'' Else ''
Label1.Text = "No internet Acess"
End Try
At least hope you gave me that
"Question Answer", it the best solution .Thanks.
(you can try it out)
Try
Dim client = New Net.WebClient
client.OpenRead("http://www.google.com")
Label21.Text = "Internet : Connected"
Catch
Label21.Text = "Internet : Disconnected"
End Try
Use this code in vb.net 100% solved, you can use this code form loading.
I am using this code and is working very well:
Public Function IsConnectedToInternet() As Boolean
If My.Computer.Network.IsAvailable Then
Try
Dim IPHost As IPHostEntry = Dns.GetHostEntry("www.google.com")
Return True
Catch
Return False
End Try
Else
Return False
End If
End Function
My.Computer.Network.Ping gave me problems so I used this function
Public Function fVerificaConnessioneInternet() As Boolean
Dim objPing As New System.Net.NetworkInformation.Ping
Try
Return If(objPing.Send("www.google.it").Status = IPStatus.Success, True, False)
Catch
Return False
End Try
End Function
or you could use this, a little better function to use. this should help you out if you need a c# version
http://www.guideushow.com/code-snippet/function-to-check-if-you-can-connect-to-the-internet-vb-net-c/
Public Function IsConnectionAvailable() As Boolean
' Returns True if connection is available
' Replace www.yoursite.com with a site that
' is guaranteed to be online - perhaps your
' corporate site, or microsoft.com
Dim objUrl As New System.Uri("http://www.google.com/")
' Setup WebRequest
Dim objWebReq As System.Net.WebRequest
objWebReq = System.Net.WebRequest.Create(objUrl)
objWebReq.Proxy = Nothing
Dim objResp As System.Net.WebResponse
Try
' Attempt to get response and return True
objResp = objWebReq.GetResponse
objResp.Close()
objWebReq = Nothing
Return True
Catch ex As Exception
' Error, exit and return False
objResp.Close()
objWebReq = Nothing
Return False
End Try
End Function