Differences

This shows you the differences between the selected revisions of the page.

2009-05-22 2009-05-25
next part (martin) almost dome except for VB.NET example (martin)
Line 1: Line 1:
-====== SFTP file transfers in .Net ====== +====== SFTP file transfers in .NET ====== 
-//This guide describes how to implement SFTP transfer in .Net application using WinSCP.//+//This guide describes how to implement SFTP transfer in .NET application using WinSCP.//
-WinSCP is SFTP client with [[scripting]] interface that you can use to automate many operations that it supports, including file transfers, synchronization and other operations. So WinSCP is not a library (e.g. .Net assembly) that you can call directly. Though this guides shows you how to use it seamlessly from the .Net code.+WinSCP is SFTP client with [[scripting]] interface that you can use to automate many operations that it supports, including file transfers, synchronization and other operations. So WinSCP is not a library (e.g. .NET assembly) that you can call directly. Though this guides shows you how to use it seamlessly from the .NET code.
Before starting you should: Before starting you should:
Line 9: Line 9:
  * [[guide_automation|Know what WinSCP scripting commands to use for your task (e.g. file transfer)]].   * [[guide_automation|Know what WinSCP scripting commands to use for your task (e.g. file transfer)]].
-===== Using WinSCP from .Net Code ===== +===== Using WinSCP from .NET Code ===== 
-To run ''[[executables|winscp.com]]'' use ''System.Diagnostics.Process''. This class allows running any executable, possibly redirecting its standard input and output to a stream accessible from .Net code. Code below expects that ''winscp.com'' (''StartInfo.FileName'') can be found (in current working directory or in search path), you need to provide full path otherwise.+To run ''[[executables|winscp.com]]'' use ''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx|System.Diagnostics.Process]]''. This class allows running any executable, possibly redirecting its standard input and output to a stream accessible from .NET code. Code below expects that ''winscp.com'' (''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.filename.aspx|ProcessStartInfo.FileName]]'') can be found (in current working directory or in search path). You need to provide full path otherwise.
-We can use standard input redirection (''StartInfo.RedirectStandardInput'') to feed [[script_commands|scripting commands]], sparing necessity to assemble temporary script file.((Of course unless what you plan to do is actually execution of existing script file.)) +You can use standard input redirection (''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardinput.aspx|ProcessStartInfo.RedirectStandardInput]]'') to feed [[script_commands|scripting commands]], sparing necessity to assemble temporary script file.((Of course unless what you plan to do is actually execution of existing script file.))
Redirection of standard output is less useful, as it does not have any predefined form (cannot be parsed). But it can be useful to capture it, in case you want to show it to a user in your GUI or for diagnostic purposes. Redirection of standard output is less useful, as it does not have any predefined form (cannot be parsed). But it can be useful to capture it, in case you want to show it to a user in your GUI or for diagnostic purposes.
-To capture results of script, we can use [[logging_xml|XML logging]]. For this we need to instruct WinSCP to stored log file using ''/log'' [[commandline|command-line parameter]] (''StartInfo.Arguments'').+To capture results of script, you can use [[logging_xml|XML logging]]. For this you need to instruct WinSCP to store log file using ''/log'' [[commandline|command-line parameter]] (''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.arguments.aspx|ProcessStartInfo.Arguments]]'').
<code csharp> <code csharp>
const string logname = "log.xml"; const string logname = "log.xml";
-System.Diagnostics.Process winscp = new System.Diagnostics.Process();+Process winscp = new Process();
winscp.StartInfo.FileName = "winscp.com"; winscp.StartInfo.FileName = "winscp.com";
winscp.StartInfo.Arguments = "/log=" + logname; winscp.StartInfo.Arguments = "/log=" + logname;
Line 30: Line 30:
</code> </code>
-To feed commands to standard input use ''StandardInput'' stream:+To feed commands to standard input use ''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardinput.aspx|Process.StandardInput]]'' stream:
<code csharp> <code csharp>
Line 47: Line 47:
</code> </code>
-If you want to collect the output, redirect the standard output before starting WinSCP (''RedirectStandardOutput'') and read from output stream (''StandardOutput''). You need to collect the output before calling ''WaitForExit''. The output stream has limited capacity. Once it gets filled, WinSCP hangs waiting for free space, never finishing.+If you want to collect the output, redirect the standard output before starting WinSCP (''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput.aspx|ProcessStartInfo.RedirectStandardOutput]]'') and read from output stream (''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx|Process.StandardOutput]]''). You need to collect the output before calling ''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.process.waitforexit.aspx|Process.WaitForExit]]''. The output stream has limited capacity. Once it gets filled, WinSCP hangs waiting for free space, never finishing.
<code csharp> <code csharp>
Line 55: Line 55:
</code> </code>
 +Once WinSCP script finishes, you should [[guide_automation#results|check the results]]. First check exit code (''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.process.exitcode.aspx|Process.ExitCode]]'')
 +of the process:
 +
 +<code csharp>
 +if (winscp.ExitCode != 0)
 +{
 +    /// Error processing
 +}
 +else
 +{
 +    /// Success processing
 +}
 +</code>
 +
 +To analyse results further, you may parse and interpret the XML log. First learn about [[logging_xml|XML logging]] to understand basic concepts.
 +
 +The .NET library offers several classes for handling XML documents. The following example uses ''[[http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathdocument.aspx|System.Xml.XPath.XPathDocument]]'' class.
 +
 +<code csharp>
 +XPathDocument log = new XPathDocument(logname);
 +XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
 +ns.AddNamespace("w", "http://winscp.net/schema/session/1.0");
 +XPathNavigator nav = log.CreateNavigator();
 +</code>
 +
 +In case of error you may check for ''[[logging_xml#result|message]]'' elements to capture any associated error messages:
 +
 +<code csharp>
 +foreach (XPathNavigator message in nav.Select("//w:message", ns))
 +{
 +    Console.WriteLine(message.Value);
 +}
 +</code>
 +
 +In case of success, you can extract directory listing generated by ''[[script_commands#ls|ls]]'' command inside ''[[logging_xml#ls|ls]]'' element:
 +
 +<code csharp>
 +XPathNodeIterator files = nav.Select("//w:file", ns);
 +Console.WriteLine(string.Format("There are {0} files and subdirectories:", files.Count));
 +foreach (XPathNavigator file in files)
 +{
 +    Console.WriteLine(file.SelectSingleNode("w:filename/@value", ns).Value);
 +}
 +</code>
 +
 +===== Full C# Example =====
 +Individual parts of this example are explained in the previous chapter.
 +
 +<code csharp>
 +using System;
 +using System.Diagnostics;
 +using System.Xml;
 +using System.Xml.XPath;
 +
 +...
 +
 +const string logname = "log.xml";
 +
 +/// Run hidden WinSCP process
 +Process winscp = new Process();
 +winscp.StartInfo.FileName = "winscp.com";
 +winscp.StartInfo.Arguments = "/log=" + logname;
 +winscp.StartInfo.UseShellExecute = false;
 +winscp.StartInfo.RedirectStandardInput = true;
 +winscp.StartInfo.RedirectStandardOutput = true;
 +winscp.StartInfo.CreateNoWindow = true;
 +winscp.Start();
 +
 +/// Open the session
 +winscp.StandardInput.WriteLine("option batch abort");
 +winscp.StandardInput.WriteLine("option confirm off");
 +winscp.StandardInput.WriteLine("open mysession");
 +winscp.StandardInput.WriteLine("ls");
 +winscp.StandardInput.WriteLine("put d:\\examplefile.txt");
 +winscp.StandardInput.Close();
 +
 +/// Collect all output (not used in this example)
 +string output = winscp.StandardOutput.ReadToEnd();
 +
 +/// Wait until WinSCP finishes
 +winscp.WaitForExit();
 +
 +/// Parse and interpret the XML log
 +/// (Note that in case of fatal failure the log file may not exist at all)
 +XPathDocument log = new XPathDocument(logname);
 +XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
 +ns.AddNamespace("w", "http://winscp.net/schema/session/1.0");
 +XPathNavigator nav = log.CreateNavigator();
 +
 +/// Success (0) or error?
 +if (winscp.ExitCode != 0)
 +{
 +    Console.WriteLine("Error occured");
 +
 +    /// See if there are any messages associated with the error
 +    foreach (XPathNavigator message in nav.Select("//w:message", ns))
 +    {
 +        Console.WriteLine(message.Value);
 +    }
 +}
 +else
 +{
 +    // It can be worth looking for directory listing even in case of
 +    // error as possibly only upload may fail
 +   
 +    XPathNodeIterator files = nav.Select("//w:file", ns);
 +    Console.WriteLine(string.Format("There are {0} files and subdirectories:", files.Count));
 +    foreach (XPathNavigator file in files)
 +    {
 +        Console.WriteLine(file.SelectSingleNode("w:filename/@value", ns).Value);
 +    }
 +}
 +</code>
 +
 +===== Full VB.NET Example =====
TODO TODO

Last modified: by martin