0 votes
by (160 points)
edited

I discovered last night that Rebex does not work on Console or Windows Service .NET application modes.

If I run it from a desktop application, it works. If I run it from a Console or Windows Service application, the upload creates a file of 0 byte on the destination SFTP server, runs in an infinite loop, causes UploadCallBack() to be called immediately, which causes the infinite loop as the lSftpWorking is never set to False, and causes a Just In Time error.

Is this a known situation on your end?

If yes, what do you recommend?

Applies to: Rebex SFTP
by (58.9k points)
edited

Please post the piece of code in which you have troubles with your Rebex component.

Please also create the log as described in this article and then send the log file together with the code snippet back to us by email or upload it as a comment to this forum post.

We will be able to look into your issue then.

2 Answers

0 votes
by (160 points)
edited

Here is the portion from the FTP class Upload() method I have in regards to Rebex simplified so just to keep the relevant information:

            oSftp = New Rebex.Net.Sftp

            ' Set event handlers
            AddHandler oSftp.TransferProgress, AddressOf TransferProgressProxy

            ' If something is working
            If lSftpWorking Then
                cMessage = cWorking
                Exit Try
            End If

            lSftpWorking = True

            ' Connect
            oSftp.Options = oSftp.Options Or Rebex.Net.SftpOptions.UseLargeBuffers
            oSftp.Timeout = 30000

            loIAsyncResult = oSftp.BeginConnect(cHost, nPort, Nothing, Nothing, Nothing)

            ' While this is not completed
            While Not loIAsyncResult.IsCompleted
                Windows.Forms.Application.DoEvents()
                System.Threading.Thread.Sleep(1)
            End While

            oSftp.EndConnect(loIAsyncResult)

            ' Login
            oSftp.Login(cUsername, cPassword)

            ' Initialization
            lSftpWorking = True

            oSftp.BeginUpload(cLocalFile, cRemoteDirectory, _
             Rebex.IO.TraversalMode.Recursive, Rebex.IO.TransferMethod.Copy, Rebex.IO.ActionOnExistingFiles.ThrowException, _
             New AsyncCallback(AddressOf UploadCallback), Nothing)

            ' Until the upload is not completed
            Do While lSftpWorking

                ' Wait a quarter second before proceding
                System.Threading.Thread.Sleep(250)

                lnUploaded = nSftpByteTransferred

                lnActual = lnUploaded / nSize * 100
                lnActualABS = Math.Abs(lnActual)

                lnElapse = ((Date.Now.Ticks - lnStart) / 10000000)

                lcMinute = oApp.SecondToFormat(lnElapse)

                lnRemaining = nSize - lnUploaded

                lnLast = lnActualABS
            Loop

This is the UploadCallBack() method:

' Callback for upload finished
Private Function UploadCallback(ByVal toIAsyncResult As IAsyncResult) As Boolean

    Try
        oSftp.EndUpload(toIAsyncResult)
        SafeInvoke(New TransferFinishedDelegate(AddressOf TransferFinished), New Object() {Nothing, True})
    Catch loError As Exception
        SafeInvoke(New TransferFinishedDelegate(AddressOf TransferFinished), New Object() {loError, True})
    End Try

    lSftpWorking = False

    Return True
End Function

Those are relevant methods:

' Establishes the event for the transfer progress
Private Sub TransferProgressProxy(ByVal toSender As Object, ByVal toSftpTransferProgressEventArgs As Rebex.Net.SftpTransferProgressEventArgs)
    SafeInvoke(New Rebex.Net.SftpTransferProgressEventHandler(AddressOf Me.TransferProgress), New Object() {toSender, toSftpTransferProgressEventArgs})
End Sub

' Event for the transfer progress
Private Sub TransferProgress(ByVal toSender As Object, ByVal toSftpTransferProgressEventArgs As Rebex.Net.SftpTransferProgressEventArgs)

    ' If we have some new data
    If toSftpTransferProgressEventArgs.BytesSinceLastEvent > 0 Then
        nSftpByteTransferred = nSftpByteTransferred + toSftpTransferProgressEventArgs.BytesSinceLastEvent
    End If

End Sub

This methods is only called at the end on a desktop application. However, from a Console or Windows Service application, it is being called right away after it created the file on the FTP server with 0 byte. So, as this method is called right away, the process never finishes as it is not normal this method is called before the file is being completely uploaded.

I cannot post the log online but you will receive it by email.

0 votes
by (58.9k points)
edited

Thank you for the log file - we can see that your application fails in the TransferProgress event, when calling the SafeInvoke method. This results in the failed upload as well.

It looks like you simply converted one of our Sftp WinForm samples, but please note that the namespace ‚System.Windows.Forms‘ is definitelly not guaranteed to work under Console or Windows Service applications.

Moreover SafeInvoke is a method we programmed specially for our WinForms sample and it should not be needed at all in a Windows Service or Console application.

In case you really want to have it there, we suggest that you fix the NullReference exception which occurs somewhere in the SafeInvoke method and can be seen in the log you sent. The exception occurs in the SafeInvoke method, not in Rebex components (last called method is the first on the stacktrace.):

2013-09-27 11:19:21.556 ERROR Sftp(1)[9] Info: System.NullReferenceException: Object reference not set to an instance of an object.
   at Framework.FTP.SafeInvoke(Delegate tcMethod, Object[] toArguments)
   at Framework.FTP.TransferProgressProxy(Object toSender, SftpTransferProgressEventArgs toSftpTransferProgressEventArgs)
   at Rebex.Net.Sftp.OnTransferProgress(SftpTransferProgressEventArgs e)
   at Rebex.Net.Sftp.1iVjn9Z(Object , SftpTransferState , Boolean , Int64 , Int64 , String , String , 27NpLhZ , Int64& , Int64& , Int32& )
   at Rebex.Net.Sftp.1xTmHi(Qu2Ci , udycp , String , Stream , Int64 , Int64 , 27NpLhZ )
...