Differences

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

guide_dotnet 2011-03-25 guide_dotnet 2020-12-25 (current)
Line 1: Line 1:
====== SFTP file transfers in .NET ====== ====== SFTP file transfers in .NET ======
 +**//Techniques demonstrated by this article are implemented for you in [[library|WinSCP .NET assembly]]. Using the assembly is recommended approach over implementing these techniques on your own.//**
 +
//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. 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. So WinSCP itself is not a library (e.g. [[library|.NET assembly]]) that you can call directly. Though this guide shows you how to use it seamlessly from the .NET code. 
 + 
 +===== Before Starting =====
Before starting you should: Before starting you should:
Line 10: Line 14:
===== Using WinSCP from .NET Code ===== ===== Using WinSCP from .NET Code =====
 +
==== [[running]] Running WinSCP Process ==== ==== [[running]] Running WinSCP Process ====
-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.+To run ''[[executables|winscp.com]]'' use ''[[dotnet>system.diagnostics.process|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'' (''[[dotnet>system.diagnostics.processstartinfo.filename|ProcessStartInfo.FileName]]'') can be found in current working directory or in search path. You need to provide full path otherwise.
<code csharp> <code csharp>
Process winscp = new Process(); Process winscp = new Process();
Line 21: Line 26:
==== [[input]] Feeding scripting commands using standard input ==== ==== [[input]] Feeding scripting commands using standard input ====
-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.)) +You can use standard input redirection (''[[dotnet&gt;system.diagnostics.processstartinfo.redirectstandardinput|ProcessStartInfo.RedirectStandardInput]]'') to feed [[scripting#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.))
-To feed commands to standard input use ''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardinput.aspx|Process.StandardInput]]'' stream:+To feed commands to standard input use ''[[dotnet&gt;system.diagnostics.process.standardinput|Process.StandardInput]]'' stream:
<code csharp> <code csharp>
Line 40: Line 45:
While you can redirect standard output of WinSCP process, it is actually not very useful, as output of WinSCP does not have any predefined form (cannot be parsed). Though it can be useful to capture it, in case you want to show it to a user in your GUI or for diagnostic purposes. While you can redirect standard output of WinSCP process, it is actually not very useful, as output of WinSCP does not have any predefined form (cannot be parsed). Though it can be useful to capture it, in case you want to show it to a user in your GUI or for diagnostic purposes.
-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. +If you want to collect the output, redirect the standard output before starting WinSCP (''[[dotnet&gt;system.diagnostics.processstartinfo.redirectstandardoutput|ProcessStartInfo.RedirectStandardOutput]]'') and read from output stream (''[[dotnet&gt;system.diagnostics.process.standardoutput|Process.StandardOutput]]''). You need to continuously collect the output while the script is running. The output stream has limited capacity. Once it gets filled, WinSCP hangs waiting for free space, never finishing. That means you cannot use ''[[dotnet&gt;system.diagnostics.process.waitforexit|Process.WaitForExit]]'' on its own to wait for script to finish. Convenient alternative is ''[[dotnet>system.io.streamreader.readtoend|StreamReader.ReadToEnd]]'':
<code csharp> <code csharp>
winscp.StartInfo.RedirectStandardOutput = true; winscp.StartInfo.RedirectStandardOutput = true;
Line 49: Line 53:
==== [[log]] Using log file ===== ==== [[log]] Using log file =====
-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]]'').+To capture results of script, you can use [[logging_xml|XML logging]]. For this you need to instruct WinSCP to store log file using ''[[commandline#logging|/xmllog]]'' command-line parameter (''[[dotnet&gt;system.diagnostics.processstartinfo.arguments|ProcessStartInfo.Arguments]]'').
<code csharp> <code csharp>
const string logname = "log.xml"; const string logname = "log.xml";
... ...
-winscp.StartInfo.Arguments = "/log=" + logname;+winscp.StartInfo.Arguments = "/xmllog=\"" + logname + "\"";
... ...
winscp.Start(); winscp.Start();
</code> </code>
-Note that before you can safely start reading and parsing the XML log file using tree-based parser (such as ''[[http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.aspx|XmlDocument]]'' or ''[[http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathdocument.aspx|XPathDocument]]''), you need to [[guide_dotnet#exit|wait for WinSCP to finish]]. If you need to read the log file continuously, you need to use stream-based parser (such as ''[[http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.aspx|XmlReader]]'').+Note that before you can safely start reading and parsing the XML log file using tree-based parser (such as ''[[dotnet&gt;system.xml.xmldocument|XmlDocument]]'' or ''[[dotnet&gt;system.xml.xpath.xpathdocument|XPathDocument]]''), you need to [[#exit|wait for WinSCP to finish]]. See example below.
-Following example shows how to use ''XPathDocument'':+If you need to read the log file continuously, you need to use stream-based parser (such as ''[[dotnet>system.xml.xmlreader|XmlReader]]''). See [[guide_interpreting_xml_log#continuous|example]]. 
 + 
 +Following example shows how to use tree-based parsing using ''XPathDocument'':
<code csharp> <code csharp>
Line 79: Line 85:
</code> </code>
-In case of success, you can e.g. extract directory listing generated by ''[[script_commands#ls|ls]]'' command inside ''[[logging_xml#ls|ls]]'' element:+In case of success, you can e.g. extract directory listing generated by ''[[scriptcommand_ls|ls]]'' command inside ''[[logging_xml#ls|ls]]'' element:
<code csharp> <code csharp>
XPathNodeIterator files = nav.Select("//w:file", ns); XPathNodeIterator files = nav.Select("//w:file", ns);
-Console.WriteLine(string.Format("There are {0} files and subdirectories:", files.Count));+Console.WriteLine("There are {0} files and subdirectories:", files.Count);
foreach (XPathNavigator file in files) foreach (XPathNavigator file in files)
{ {
Line 89: Line 95:
} }
</code> </code>
 +
 +//See also guide to [[guide_interpreting_xml_log|*]].//
==== [[exit]] Waiting for script to complete ==== ==== [[exit]] Waiting for script to complete ====
-Use ''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.process.waitforexit.aspx|Process.WaitForExit]]'' to wait for WinSCP process to finish. +Use ''[[dotnet&gt;system.diagnostics.process.waitforexit|Process.WaitForExit]]'' to wait for WinSCP process to finish.
-If you have output stream redirected, you need to first [[guide_dotnet#output|read the output stream to the end]].+If you have output stream redirected, you need to first [[#output|read the output stream to the end]].
A good practice is to close input stream too, if you have it redirected. A good practice is to close input stream too, if you have it redirected.
Line 107: Line 115:
==== [[exitcode]] Checking exit code ==== ==== [[exitcode]] Checking exit code ====
-Once WinSCP script finishes, check exit code (''[[http://msdn.microsoft.com/en-us/library/system.diagnostics.process.exitcode.aspx|Process.ExitCode]]'')+Once WinSCP script finishes, check exit code (''[[dotnet&gt;system.diagnostics.process.exitcode|Process.ExitCode]]'')
of the process: of the process:
Line 137: Line 145:
Process winscp = new Process(); Process winscp = new Process();
winscp.StartInfo.FileName = "winscp.com"; winscp.StartInfo.FileName = "winscp.com";
-winscp.StartInfo.Arguments = "/log=" + logname;+winscp.StartInfo.Arguments = "/xmllog=\"" + logname + "\"";
winscp.StartInfo.UseShellExecute = false; winscp.StartInfo.UseShellExecute = false;
winscp.StartInfo.RedirectStandardInput = true; winscp.StartInfo.RedirectStandardInput = true;
Line 182: Line 190:
       
    XPathNodeIterator files = nav.Select("//w:file", ns);     XPathNodeIterator files = nav.Select("//w:file", ns);
-    Console.WriteLine(string.Format("There are {0} files and subdirectories:", files.Count));+    Console.WriteLine("There are {0} files and subdirectories:", files.Count);
    foreach (XPathNavigator file in files)     foreach (XPathNavigator file in files)
    {     {
Line 208: Line 216:
Dim winscp As Process = New Process() Dim winscp As Process = New Process()
winscp.StartInfo.FileName = "winscp.com" winscp.StartInfo.FileName = "winscp.com"
-winscp.StartInfo.Arguments = "/log=" + logname+winscp.StartInfo.Arguments = "/xmllog=" + logname
winscp.StartInfo.UseShellExecute = False winscp.StartInfo.UseShellExecute = False
winscp.StartInfo.RedirectStandardInput = True winscp.StartInfo.RedirectStandardInput = True
Line 252: Line 260:
       
    Dim files As XPathNodeIterator = nav.Select("//w:file", ns)     Dim files As XPathNodeIterator = nav.Select("//w:file", ns)
-    Console.WriteLine(string.Format("There are {0} files and subdirectories:", files.Count))+    Console.WriteLine("There are {0} files and subdirectories:", files.Count)
    For Each file As XPathNavigator In files     For Each file As XPathNavigator In files
        Console.WriteLine(file.SelectSingleNode("w:filename/@value", ns).Value)         Console.WriteLine(file.SelectSingleNode("w:filename/@value", ns).Value)

Last modified: by martin