Post a reply

Options
Add an Attachment

If you do not want to add an Attachment to your Post, please leave the Fields blank.

(maximum 10 MB; please compress large files; only common media, archive, text and programming file formats are allowed)

Options

Topic review

martin

Re: WinSCP Automation - Connection has been unexpectedly closed. Server sent command exit status

Sorry, that' too many questions for one post. Let focus on the logs first.
Ignore the XML log. Debug log level 0 is ok for a start.

Non-responding: You cannot run a blocking operation on the GUI thread. You have to run it on a background thread.
See for example this topic:
Showing WinSCP .NET assembly transfer progress on WinForm's progress bar
It's for VB.NET, but it should be easy to rewrite it to C#.
bhushan80

WinSCP Automation - Connection has been unexpectedly closed. Server sent command exit status

Hello Martin,

Thank you very much for your prompt response. FYI, following the guidelines on this website, I was able to properly close and dispose the Sftp session. The issue occurred on someone else's machine who has an EXE without Debug / Session logs enabled. However, sensing the need, I have already enabled the debug / session logs now and they are being generated at my end and should the error occur again, I shall share the logs. Meanwhile, I have used below code to create the debug / session log files:
try
{
    dbgLogFile = Path.Combine(dbgLogDir, Process.GetCurrentProcess().ProcessName + "_" + Process.GetCurrentProcess().Id + "_WinSCPDebugLog_" +
        DateTime.Now.ToShortDateString().Replace('/', '_') + "_" + DateTime.Now.ToShortTimeString().Replace(':', '_') + ".log");
    if (File.Exists(dbgLogFile)) { File.Delete(dbgLogFile); }
    session.DebugLogLevel = 2;   // need debug logging level understanding as I was unable to find any documentation
    session.DebugLogPath = dbgLogFile;
}
catch (IOException e1)
{
    // Handle the exception...
    session.DebugLogLevel = 0;
    session.DebugLogPath = null;
}
catch (UnauthorizedAccessException dbgUAEEx)
{
    // Handle the exception...
    session.DebugLogLevel = 0;
    session.DebugLogPath = null;
}
catch (Exception dbgEx)
{
    // Catch and handle any exception
    session.DebugLogLevel = 0;
    session.DebugLogPath = null;
}

I have put similar code in place for the session and Xml logs as well. Both debug and session logs are being generated, but XML log file is never created. I am not sure what it logs and if and when I would need it. Requesting you to provide more info as to if I would need them and what is the use-case.

I have kept the logs configurable to avoid excessive logging. Still it would be good to know if the above code passes your review and if I can get some understanding of debug log levels. What will happen if I set it to 0? Will the log file be created at all? And what sort of logging is done at different levels?

With regards to do multiple transfers also, I verified by opening multiple instances of our application and initiating the transfers simultaneously. Although the total transfer batch size was not significant, it worked indicating that it is not a hurdle.

However, even with 1 instance of our application running, if I schedule a large file to upload, the application becomes unresponsive. I understand that this is not a issue with WinSCP, but I just want to know whether or not, the solution provided by you would solve the problem? In the link you shared, it is demonstrating opening multiple sessions. In my case, am fine with a single session for now. I am more interested in doing it in a Async fashion or any other fashion that would be non-blocking. Nevertheless, I shall give it a try and report here.

Also, presently I am using session.Putfiles method to upload the files to the server. However, if I want to get progress report for large files, is Synchronize the only option I have? I am a little hesitant to use it because I am creating all the instances dynamically and attaching Event Handlers and raising Events becomes super difficult and hence I was avoiding it till this point of time. The problem is creating a EventArgs to match the delegate signature using reflection. For that we have to create an in-memory assembly which is huge overhead for a trivial task as this.

Thank you for your assistance so far. I shall update you and other watching this thread if I make some progress on this.

Regards,
Bhushan
martin

Re: WinSCP Automation - Connection has been unexpectedly closed. Server sent command exit status

Please attach a full session log file showing the problem (using the latest version of WinSCP).

To generate the session log file, set Session.SessionLogPath. Submit the log with your post as an attachment. Note that passwords and passphrases not stored in the log. You may want to remove other data you consider sensitive though, such as host names, IP addresses, account names or file names (unless they are relevant to the problem). If you do not want to post the log publicly, you can mark the attachment as private.


Regarding parallel transfers, see:
Automating transfers or synchronization in parallel connections over SFTP/FTP protocol
bhushan80

WinSCP Automation - Connection has been unexpectedly closed. Server sent command exit status

Hello,
This is my very first post here and I am very much impressed by the simplicity of the ways to work with the WinSCP client. However, as always there are challenges, that need to be overcome and sometimes get better of you. So here it goes...

We are currently working on replacing a certain file transfer across the network using Windows shared paths by invoking WinSCP and thus automating the existing manual process with SFTP. So in the existing application, I have created a class to expose the relevant APIs and it works fine the first time. However, the problem starts when I try to initiate another set of file transfers. I am presented with the exception:
Connection has been unexpectedly closed. Server sent command exit status 0.

So in my application, I am not instantiating the session and its related members using the sample code. Instead, we are loading WinSCPNet.dll dynamically at runtime. 2 reasons for doing this:

  1. The usual add reference mechanism always kept giving me exceptions as I tried adding reference and specifying the executable path as well as I tried adding the assembly directly from the WinSCP install location.
  2. Another reason to go for the overhead of not adding a reference and writing the extra code to load the assembly at runtime was to put the onus of installation of WinSCP on the end user and assuming this makes clear distinction of the responsibilities to be handled.
    Approach 2 is working for me in a simple scenario.

However, following are the issues faced currently:

  1. As I do one complete cycle of uploading files to the predefined SFTP location, I close the connection (and never dispose it). I have put session.Opened checks before starting the new cycle to check and open a new session to start a new cycle which is failing with the error:
    Connection has been unexpectedly closed. Server sent command exit status 0.
    So what has to be done to get past it? Just to add, I cannot use the braces to dispose the session object as I have declared it in a wrapper class and this class has methods exposed to the outside world to do stuff. I have not even implemented Dispose yet and with the application still running, we were not expecting this error. If it is about Session.Timeout / ReconnectionTime or the relevant options in SessionOptions, kindly assist me as to how do I set these properly, so that the session never times out or atleast stays alive till the user COB.
  2. How should I properly call Dispose on all the relevant WinSCP objects, that I am creating using "dynamic" type in C#? I intend to do it when the user exits the application. For example,

public class WinSCPExtension
{
    private dynamic sessionOptions
    public dynamic session
    private dynamic AnyOtherWinSCPSpecificObject
 
    public void InitializeSession()
    {
        // called from outside the class...
        myWinSCPNetAssembly = Assembly.LoadFrom(PathToWinSCPNetdll));
        var sessionOptionsType = myWinSCPNetAssembly.GetType("WinSCP.SessionOptions");
        sessionOptions = Activator.CreateInstance(sessionOptionsType);
        ...
        ...
        sessionOptions.HostName = hostName;
        sessionOptions.UserName = userName;
        sessionOptions.Password = pwd;
        sessionOptions.SshHostKeyFingerprint = SftpSshHostKeyFingerprint;
       
        var sessionType = myWinSCPNetAssembly.GetType("WinSCP.Session");
        session = Activator.CreateInstance(sessionType);
        session.ExecutablePath = PathToWinSCPEXE;
        ....
    }
 
    public void OpenSession()
    {
        ....
        if (!session.Opened)
        session.Open(sessionOptions);
        ....
        ....
        // Do more stuff...
    }
 
    public void CloseSession()
    {
       if(session.Opened) session.Close();
    }
 
    ...
    // Presently there is no dispose implemented.
}

[3] How do I set the transfers to happen in back ground via C#? And how do I handle concurrency? It may so happen that the user may launch multiple instances of the .NET application and try to do multiple transfers simultaneously. What should happen in that scenario as one session running under existing instance would have transfers scheduled and user would try to pass in same credentials from another application instance to create another session.

I have tried to put the details in a best possible manner so that it is easy to understand the scenario. Kindly assist me further to understand the pitfalls at the earliest.

Regards,
Bhushan