How to check if the connection to a SFTP server is successful using WinSCP in VB.NET - vb.net

I have sent a file by SFTP to another server using WinSCP in VB.NET.
I would like to see if the connection was successful or not.
I also need to know if the file already exists in the directory beforehand.

There are a couple of things you can do. You can create a session log that tells you (in a LOT of detail) what happened during your file transfer. You can also put a try-catch block around mySession.Open(mySessionOptions) to catch an error.
Finally, use mySession.FileExists(remotepath) to check to see if the file is already on the server.
Dim mySessionOptions As New SessionOptions
With mySessionOptions
.Protocol = Protocol.Sftp
.HostName = "999.999.999.999"
.UserName = "login"
.Password = "mypassword"
.SshHostKeyFingerprint = "ssh-dss 1024 99:87:99:4d:99:a3:99:b9:99:15:99:f2:99:87:88:b2"
End With
Using mySession As Session = New Session
' Will continuously report progress of synchronization
AddHandler mySession.FileTransferred, AddressOf FileTransferred
' Connect
mySession.SessionLogPath = "C:\Users\yourName\yourFolder\Sessionlog.log"
'Use Try-Catch to check for error in connection
Try
mySession.Open(mySessionOptions)
Catch ex As Exception
MessageBox.show(ex.Message)
mySession.Close()
Exit Sub
End Try
'Check to see if file exist already on server
If mySession.FileExists(remotePath) Then
MessageBox.Show("File Exists on Server")
mySession.Close()
Exit Sub
End If
mySession.PutFiles("C:\Users\yourName\yourFolder\yourfile.dat", remotePath)
mySession.Close()
End Using
Remember to check the log you created to see exactly what happened.

Related

If explorer is already running

I have a system that backs up data to a network with certain parameters in place such as:
'If x process is running, do not run the backup'
Because it's connected to a network, users will constantly be on it. The problem I have is that I don't want the data to get moved onto the network if it's in use, plus, the data is unable to move across if someone is using file explorer on the same computer as the program is on.
I would use 'If explorer is running, do not run the backup' but explorer is linked to windows and is always running
If program.Count > 0 Or program2.Count > 0 Then
Try
Msgbox("Process Running")
Catch ex As Exception
End Try
Else
'backup data
End If
Is there a way to try get the program to transfer files, but if fails because the file directory is already open, then do x?
Try this. It should generate an error if you can't lock the file.
Public Function IsFileLocked(file As FileInfo) As Boolean
Dim stream = DirectCast(Nothing, FileStream)
Try
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None)
Catch generatedExceptionName As IOException
'handle the exception your way
Return True
Finally
If stream IsNot Nothing Then
stream.Close()
End If
End Try
Return False
End Function

Filestream read only locking PC

I'm trying to read the Windows update log on remote PCs on my LAN. Most of the time I can successfully read the file but at times the program locks up. Likely due to one issue or another - doesn't really matter. What I do need is a way to recover when the Filestream/Streamreader locks up - I'm not sure which is causing the lock. Some streams can set a timeout but the filestream below returns False on a .CanTimeout call.
How can I break out if the stream locks up? (Sometimes the lock is so tight a power off is needed to recover.)
Is there a way to test if the stream will fail before I actually attempt the read?
Is there an alternate way to read a remote log file that another program has open? (I'm using the stream method because the regular File.IO was blocked because the file is open on the remote PC.)
I'm getting closer (I think) with this code. I browed the pathExists code from the referenced post but it was the OP and not an answer.
Imports System.IO
Import System.Threading
...
Function GetAULog(PCName As String) As String
Try
Dim sLogPath As String = String.Format("\\{0}\c$\Windows\SoftwareDistribution\ReportingEvents.log", PCName)
If PCName = My.Computer.Name Then
sLogPath = String.Format("C:\Windows\SoftwareDistribution\ReportingEvents.log", PCName)
End If
' read file open by another process
If Not pathExists(sLogPath) Then
MsgBox("AU log file not found - PC on?")
Return "NA"
End If
Using fs As New FileStream(sLogPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
Using sr As New StreamReader(fs)
Dim s As String = sr.ReadToEnd
Return s
End Using
End Using
Catch ex As Exception
MsgBox(ex.Message)
Return ""
End Try
End Function
Public Function pathExists(path As String) As Boolean
Dim exists As Boolean = True
Dim t As New Thread(New ThreadStart(Sub() exists = System.IO.File.Exists(path)))
t.Start()
Dim completed As Boolean = t.Join(500)
'half a sec of timeout
If Not completed Then
exists = False
t.Abort()
End If
t = Nothing
Return exists
End Function
At least when the PC is off the pathExists() code returns False in short order.
My problem now is the process does not end when the program exits - at least in the IDE, didn't check runtime.
I added t = Nothing but that didn't help. I couldn't figure out the proper Using syntax to test that. How do I properly cleanup after a thread timeout?
I've had the situation with this locking until restart problem. It seems to be caused by the tcpip auto tuning feature. You can cure this issue by running
netsh interface tcp set global autotuninglevel=disable
Run this on both machines if you have access. I tried a few workarounds for this issue with checking locks etc but the only way I could solve it was to disable this. The issue is not really with locking but with something at a lower level in the file sharing protocol.
See this article for more detail
"Final" code shown below. The exceptions are not firing when the timeout occurs so the .Abort was evidently OK.
When the timeout does occur, because the remote PC did not respond, there is a process left hanging which goes away after 30 seconds or so. I notice this when using the IDE, I run the program and test a PC that is off. If I then exit the program the form closes but the IDE hangs for ~30 seconds - I can click Stop-Debugging at this point and it works, but the IDE continues on its own after the ~30 second timeout.
I guess the t = Nothing in the Finally block does not dispose of the thread. t.Dispose does not exists.
So, things are working OK with the exception of the dangling thread that eventually clears itself up. The program is no longer hanging to the point where it cannot not be stopped.
'Imports System.IO
'Imports System.Threading
Public Function pathExists(path As String) As Boolean
' check for file exists on remote PC
Dim exists As Boolean = False
Dim t As New Thread(New ThreadStart(Sub() exists = System.IO.File.Exists(path)))
Try
t.Start()
Dim completed As Boolean = t.Join(500)
'half a sec of timeout
If Not completed Then
exists = False
t.Abort()
End If
Catch ex2 As ThreadInterruptedException
MsgBox("timeout on AU log exists test" & vbNewLine & ex2.Message,, "ThreadInterruptedException")
Catch exAbort As ThreadAbortException
MsgBox("timeout on AU log exists test" & vbNewLine & exAbort.Message,, "ThreadAbortException")
Catch ex As Exception
MsgBox("exception on AU log exists test" & vbNewLine & ex.Message)
Finally
t = Nothing
End Try
Return exists
End Function

"KeepAlive" for TCPClient connection to keep connection open?

Is there a way to keep a TcpClient connection open constantly? I have an application which lets our users scan a carton, some database updates are performed, and a shipping label is sent to and printed from a wireless hip printer (model of printer is Zebra QLn420) which the user is using.
The application attempts to keep a connection to the wireless printer via the TcpClient connection, and multiple checks are made throughout processing to make sure the connection is good, before sending a generated ZPL to the printer for printing.
We have been having an issue with an occasional label missing, and it seems to be whenever the user stops scanning for a few minutes, then resumes. However, it is a semi-rare occurrence when a label is skipped, and as such is rather hard to reproduce (I haven't been able to replicate it myself, but I have seen it happen out in the warehouse).
I would like to know either if there is a way to make sure that the connection is always open (by "pinging" the device every so often), or if there is a way to get feedback that the data has been received and printed.
This is the code I'm calling to ensure a connection:
Public Function Connect(strIP As String, intPort As Integer) As Boolean
Try
'connect to printer via TcpClient, need ip address and port number
'connects without thread, hangs program for 10-20 seconds if printer is not turned on, replaced with code below to thread the connection and set timeout
For i As Integer = 1 To 2
If Not (client IsNot Nothing AndAlso client.Connected) Then
'uses ClientSocketParameters structure to pass to recursive function ConnectionReturned()
clntSockParams = New ClientSocketParameters
clntSockParams.addrs = strIP
clntSockParams.prt = intPort
'create client and call BeginConnect (attempts to connect on separate thread until TimeoutTime has elapsed)
client = New System.Net.Sockets.TcpClient
client.SendTimeout = 5000
client.ReceiveTimeout = 5000
'setup timer with timeout length and start, if timer goes past intTimeoutLength, the Timeout() function is called which closes everything and leaves client = Nothing
AddHandler TimeoutTime.Elapsed, AddressOf Timeout
TimeoutTime.Interval = intTimeoutLength
TimeoutTime.Start()
client.BeginConnect(strIP, intPort, New AsyncCallback(AddressOf ConnectionReturned), clntSockParams)
'keeps the program from doing anything else until BeginConnect either succeeds or fails (due to connect on separate thread)
Do While TimeoutTime.Enabled
System.Threading.Thread.Sleep(500)
Loop
End If
'if TimeoutTime is elapsed and client is Nothing, connection didn't happen, throw an error
If client Is Nothing Then
blnConnected = False
Else
blnConnected = True
Exit For
End If
Next
Catch ex As Exception
blnConnected = False
End Try
Return blnConnected
End Function
Private Sub ConnectionReturned(ByVal ar As System.IAsyncResult)
'this method is called from the client.BeginConnect line in Connect(), make sure timer is running
If TimeoutTime.Enabled Then
'ensure client is initialized
If client Is Nothing Then client = New System.Net.Sockets.TcpClient
'keep calling ConnectionReturned until client.Connected is true
If client.Connected Then
TimeoutTime.Stop()
Else
Dim actualParameters As ClientSocketParameters = DirectCast(ar.AsyncState, ClientSocketParameters)
client.BeginConnect(actualParameters.addrs, actualParameters.prt, New AsyncCallback(AddressOf ConnectionReturned), clntSockParams)
End If
End If
End Sub
Private Sub Timeout(ByVal sender As Object, ByVal e As EventArgs)
'this method is only called if TimeoutTime elapsed, which means no connection was made. close the client object if needed, set to Nothing, and stop TimeoutTime
If TimeoutTime.Enabled Then
Try
client.Close()
Catch ex As Exception
End Try
client = Nothing
TimeoutTime.Stop()
End If
End Sub
According to this question:
tcp client in vb.net not receiving the entire data response data from server
TcpClient is not always guaranteed to deliver all data to the other end of a connection, so if a more reliable connection method is available, that would be worth a try as well.
Please let me know if more information is needed. Thank you!
Originally I got the code for connecting via this link. I've modified it since because it would hang the application for 10-20 seconds if it took longer to connect. Code here is in C# and I translated to VB:
Send ZPL Commands via TCP/IP in C#
This is the link to the docs for the class:
TcpClient Class
Zebra printers have a timeout setting on TCP that I think has a 3 or 5 minute default. The first thing to do is to turn that timeout off. There will still be other reasons that the printer would disconnect so you will need to handle that as well.
embed this into your program:
! U1 setvar "wlan.ip.timeout.enable" "off"
Make sure you send a CR/LF before and after that line.
if you send a query after your format you can know that the whole format made it to the printer. Something like the following would work:
! U1 getvar "device.uptime"
That's not a sane solution. A sane solution is this: If a label isn't completely sent to the printer because the connection failed, make a new connection and send the label.

Simplest method for passing flag between two separate .net processes

I have two separate vb.net applications. One is a GUI frontend WinForm and the other is a console application which handles file transfers and runs in the background. The file transfer application monitors a directory and when new files are found, it transfers the files to a destination. It checks that the remote destination is accessible. I would like to have a flag which indicates the file transfer task can connect to remote destination and display this status on the GUI.
Example of how the GUI application starts the File Transfer console application:
Public FileXferProcess As Process
Dim startInfo As New ProcessStartInfo("FileXfer.exe")
startInfo.CreateNoWindow = True
startInfo.UseShellExecute = False
FileXferProcess = Process.Start(startInfo)
I know there are many different types of interprocess communication techniques but I am looking for the simplest solution for sharing a boolean state.
I ended up using a mutex to pass a flag between the separate processes. That does not require any overhead and handles if the process if abruptly closed (since the mutex will be destroyed with the task that created it).
Below are code snippets:
In File Transfer task
Public hMutex_Connected As Mutex
...
' If connected, set mutex
hMutex_Connected = New Mutex(True, "FileXfer_Connected")
...
' If disconnected, destroy mutex
hMutex_Connected.Close()
In Main application GUI
Public Function IsConnected() As Boolean
Dim bConnected As Boolean = False
Try
Mutex.OpenExisting("FileXfer_Connected")
bConnected = True
Catch ex As WaitHandleCannotBeOpenedException
' "Mutex does not exist."
Catch ex As UnauthorizedAccessException
' "Unauthorized access: " & ex.Message
Catch ex As Exception
' ex.ToString
End Try
Return bConnected
End Function

Why am I getting object reference not set error on script task connector?

I have an SSIS package (SQL Server 2005) that loops through a bunch of flat files in a folder. I need to wait until the source application has finished writing the file before I can open it in my flat file import task.
I have a For Each loop container and within it a script task to execute before the Data Flow Task.
When I try to create the success connector between the Script Task and the Data Flow Task I get this error:
Could not create connector. Object reference not set to an instance of
an object.
I get that something is being set to nothing, but I can't see it. I have DelayValidation set to true on both the Script Task and the Data Flow Task. What else am I missing?
I'm a C# guy so maybe I'm missing something obvious in the VB. Here's the script I poached from the interwebs:
Public Sub Main()
Dim strFileName As String = CType(Dts.Variables("FileName").Value, String)
Dim objFS As System.IO.FileStream
Dim bolFinished As Boolean = False
Do
Try
objFS = System.IO.File.Open(strFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
bolFinished = True
objFS.Close()
Catch ex As Exception
System.Threading.Thread.Sleep(1000)
End Try
Loop
If bolFinished Then
Dts.TaskResult = Dts.Results.Success
Else
Dts.TaskResult = Dts.Results.Failure
End If
End Sub
Milen k is more than right. It looks like you have an infinite loop which is opening a file several times until it breaks down.
You could change your code with the below suggested code. This will help you to get out of the infinite loop.
Your current code:
Do
Try
objFS = System.IO.File.Open(strFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
bolFinished = True
objFS.Close()
Catch ex As Exception
System.Threading.Thread.Sleep(1000)
End Try
Loop
Suggested code:
Do While(true)
Try
objFS = System.IO.File.Open(strFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
bolFinished = True
objFS.Close()
Exit Do
Catch ex As Exception
System.Threading.Thread.Sleep(1000)
End Try
Loop
Make sure that you have created a Flat File Source for your Data Flow task. If you do not have an existing one, create a temporary one which act as a place-holder for the file paths you feed it through the For Each loop.
From what I understand, you should be passing the path to each file that you will be importing to your Flat File Connection. This can easily be done by adding the variable generated in your For Each loop as an expression in the Expression property of your Flat File Connection.
UPDATE:
You need to set a condition in your Do ... Loop. For example: Loop While Not bolFinished. Look at this document for more information.