.NET Assemblies session.SynchronizeDirectories events

Advertisement

cazzoo
cazzoo avatar
Joined:
Posts:
5
Location:
France

.NET Assemblies session.SynchronizeDirectories events

Dear all,

I recently tried to implement SynchronizeDirectories to a new wpf app I'm building and I'm facing weird issues with events that are acting in a strange way.

The synchronization is working properly in both ways, but the progressbar is not updated during the synchronization itself, only at the end of the process. In short terms, my code is going to eventHandlers but not updating the window itself. Any ideas on that ?

Here is the code I'm using :
ProgressWindow.xaml
<Window x:Class="MyApp.SynchronizationWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="Mod synchronization" Width="500" WindowStyle="ToolWindow" SizeToContent="Height" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False" ContentRendered="Window_ContentRendered">
    <DockPanel>
        <StackPanel DockPanel.Dock="Bottom">
            <StatusBar>
                <StatusBarItem>
                    <TextBlock Name="statusText" />
                </StatusBarItem>
            </StatusBar>
        </StackPanel>
        <StackPanel Margin="0,0,0,5">
            <Label Content="Current File" />
            <Label Name="fileName" Content="" BorderThickness="0" Margin="30,0,10,0" />
            <StackPanel Margin="50,0">
                <StackPanel Orientation="Horizontal">
                    <Label Content="File progress :" />
                    <Label Name="filePercentage" Content="0%" />
                </StackPanel>
                <ProgressBar Name="fileProgress" Height="15" Foreground="#FF01D328" />
                <StackPanel Orientation="Horizontal">
                    <Label Content="Overall progress :" />
                    <Label Name="overallPercentage" Content="0%" />
                </StackPanel>
                <ProgressBar Name="overallProgress" Height="15" Foreground="#FF0160D3" />
            </StackPanel>
        </StackPanel>
    </DockPanel>
</Window>
ProgressWindow.xaml.cs
using MyApp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows;
using WinSCP;
using System.Linq;

namespace MyApp
{
    /// <summary>
    /// Interaction logic for SynchronizationWindow.xaml
    /// </summary>
    public partial class SynchronizationWindow : Window
    {
        private string _lastFileProcessed;
        private int _countFilesToSynchronize;
        private int _countFilesProcessed;
        private Action _selectedAction;

        public enum Action
        {
            DOWNLOAD,
            UPLOAD
        }

        public SynchronizationWindow(Action selectedAction)
        {
            InitializeComponent();
            ResetComponents();
            _selectedAction = selectedAction;
        }

        private void ResetComponents()
        {
            _countFilesToSynchronize = 0;
            _countFilesProcessed = 0;
            statusText.Text = null;
            fileName.Content = null;
            filePercentage.Content = "0%";
            fileProgress.Value = 0;
            overallPercentage.Content = "0%";
            overallProgress.Value = 0;
        }

        private void SynchronizeToRemote()
        {
            try
            {
                // Setup session options
                SessionOptions sessionOptions = new SessionOptions
                {
                    Protocol = Protocol.Sftp,
                    HostName = Settings.Default.RepositoryUrl,
                    UserName = Settings.Default.RepositoryName,
                    Password = Settings.Default.RepositoryPassword,
                    SshPrivateKeyPath = Settings.Default.RepositoryPrivateKeyPath,
                    PrivateKeyPassphrase = Settings.Default.RepositoryPrivateKeyPassphrase,
                    GiveUpSecurityAndAcceptAnySshHostKey = true
                };

                using (Session session = new Session())
                {
                    // Will continuously report progress of synchronization
                    session.FileTransferred += FileTransferred;

                    // Will continuously report progress of transfer
                    session.FileTransferProgress += SessionFileTransferProgress;

                    // Connect
                    session.Open(sessionOptions);

                    string localPath = Path.Combine("C:\\test");
                    string remotePath = Path.Combine(Settings.Default.RepositoryStoragePath, "test");

                    if (!session.FileExists(remotePath))
                    {
                        session.CreateDirectory(remotePath);
                    }

                    HashSet<string> filesToSynchronize = new HashSet<string>(Directory.GetFiles(localPath, "*.*", SearchOption.AllDirectories).ToList());
                    _countFilesToSynchronize = filesToSynchronize.Count;

                    SynchronizationResult synchronizationResult;
                    synchronizationResult =
                        session.SynchronizeDirectories(SynchronizationMode.Remote, localPath, remotePath, true);

                    // Throw on any error
                    synchronizationResult.Check();

                    StringBuilder failedFiles = new StringBuilder();
                    foreach (TransferEventArgs failedFile in synchronizationResult.Failures)
                    {
                        failedFiles.AppendLine(string.Format("{0}", failedFile.FileName));
                    }

                    if (failedFiles.Length > 0)
                    {
                        MessageBox.Show(failedFiles.ToString(), "Error uploading files.");
                    }

                    if (synchronizationResult.IsSuccess)
                    {
                        overallPercentage.Content = string.Format("{0:P0}", 1);
                        overallProgress.Value = 100;
                        statusText.Text = "Operation succeeded.";
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: {0}", ex);
            }
        }

        private void SynchronizeToLocal()
        {
            try
            {
                // Setup session options
                SessionOptions sessionOptions = new SessionOptions
                {
                    Protocol = Protocol.Sftp,
                    HostName = Settings.Default.RepositoryUrl,
                    UserName = Settings.Default.RepositoryName,
                    Password = Settings.Default.RepositoryPassword,
                    SshPrivateKeyPath = Settings.Default.RepositoryPrivateKeyPath,
                    PrivateKeyPassphrase = Settings.Default.RepositoryPrivateKeyPassphrase,
                    GiveUpSecurityAndAcceptAnySshHostKey = true
                };

                using (Session session = new Session())
                {
                    // Will continuously report progress of synchronization
                    session.FileTransferred += FileTransferred;

                    // Will continuously report progress of transfer
                    session.FileTransferProgress += SessionFileTransferProgress;

                    // Connect
                    session.Open(sessionOptions);

                    string localPath = Path.Combine("C:\\test");
                    string remotePath = Path.Combine(Settings.Default.RepositoryStoragePath, "test");

                    if (!session.FileExists(remotePath))
                    {
                        MessageBox.Show(string.Format("The mod [{0}] doesn't exist in the remote repository [{1}].", Mod.Name, Settings.Default.RepositoryStoragePath));
                        return;
                    }

                    if (!Directory.Exists(localPath))
                    {
                        Directory.CreateDirectory(localPath);
                    }
                    RemoteDirectoryInfo remoteDirectoryInfo = session.ListDirectory(remotePath);
                    _countFilesToSynchronize = remoteDirectoryInfo.Files.Count;

                    SynchronizationResult synchronizationResult;
                    synchronizationResult =
                        session.SynchronizeDirectories(SynchronizationMode.Local, localPath, remotePath, true);

                    // Throw on any error
                    synchronizationResult.Check();

                    StringBuilder failedFiles = new StringBuilder();
                    foreach (TransferEventArgs failedFile in synchronizationResult.Failures)
                    {
                        failedFiles.AppendLine(string.Format("{0}", failedFile.FileName));
                    }

                    if (failedFiles.Length > 0)
                    {
                        MessageBox.Show(failedFiles.ToString(), "Error downloading files.");
                    }

                    if (synchronizationResult.IsSuccess)
                    {
                        overallPercentage.Content = string.Format("{0:P0}", 1);
                        overallProgress.Value = 100;
                        statusText.Text = "Operation succeeded.";
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: {0}", ex);
            }
        }

        private void FileTransferred(object sender, TransferEventArgs e)
        {
            string returnMessage = string.Empty;
            if (e.Error == null)
            {
                returnMessage = $"Upload of {e.FileName} succeeded";
            }
            else
            {
                returnMessage = $"Upload of {e.FileName} failed: {e.Error}";
            }

            if (e.Chmod != null)
            {
                if (e.Chmod.Error == null)
                {
                    returnMessage = $"Permissions of {e.Chmod.FileName} set to {e.Chmod.FilePermissions}";
                }
                else
                {
                    returnMessage = $"Setting permissions of {e.Chmod.FileName} failed: {e.Chmod.Error}";
                }
            }
            else
            {
                returnMessage = $"Permissions of {e.Destination} kept with their defaults";
            }

            if (e.Touch != null)
            {
                if (e.Touch.Error == null)
                {
                    returnMessage = string.Format("Timestamp of {0} set to {1}", e.Touch.FileName, e.Touch.LastWriteTime);
                }
                else
                {
                    returnMessage = string.Format("Setting timestamp of {0} failed: {1}", e.Touch.FileName, e.Touch.Error);
                }
            }
            else
            {
                // This should never happen during "local to remote" synchronization
                returnMessage = string.Format("Timestamp of {0} kept with its default (current time)", e.Destination);
            }
            Console.WriteLine(returnMessage);
            statusText.Text = returnMessage;

            UpdateOverallProgress();
        }

        private void UpdateOverallProgress()
        {
            _countFilesProcessed++;
            double currentOverallPercentage = (double)_countFilesProcessed / _countFilesToSynchronize;
            overallPercentage.Content = string.Format("{0:P0}", currentOverallPercentage);
            overallProgress.Value = currentOverallPercentage * 100;
        }

        private void SessionFileTransferProgress(object sender, FileTransferProgressEventArgs e)
        {
            // New line for every new file
            if (_lastFileProcessed != null && _lastFileProcessed != e.FileName)
            {
                fileName.Content = String.Format("File [{0}] processed.", e.FileName);
            }

            // Print transfer progress
            string percentage = String.Format("{0:P1}", e.FileProgress);
            filePercentage.Content = percentage;
            fileProgress.Value = e.FileProgress * 100;

            // Remember a name of the last file reported
            _lastFileProcessed = e.FileName;
        }

        private void Window_ContentRendered(object sender, EventArgs e)
        {
            switch (_selectedAction)
            {
                case Action.DOWNLOAD:
                    SynchronizeToLocal();
                    break;

                case Action.UPLOAD:
                    SynchronizeToRemote();
                    break;
            }
        }
    }
}

Thanks in advance for any hints.
Regards,
Caz

Reply with quote

Advertisement

martin
Site Admin
martin avatar
Joined:
Posts:
41,518
Location:
Prague, Czechia

Re: .NET Assemblies session.SynchronizeDirectories events

I do not know WPF, but I assume that as with WinForms, you have to run lenghty operations on a background thread, not on GUI thread.

See an example for WinForms and VB.NET at:
https://stackoverflow.com/q/33012517/850848

Or this WPF question with a link to a generic question (not about WinSCP):
https://stackoverflow.com/q/43364376/850848

Reply with quote

Advertisement

You can post new topics in this forum