Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Simple Way to Develop Server Software for File Manipulation

0.00/5 (No votes)
16 Mar 2012 1  
This is a simple server software for copying file from one directory to other but the technique can be used to develop in any server software.

Introduction

Over the past years, I've learned many things from CodeProject and now I want to give something to CodeProject. In many Winform applications, we might have to wait for a user to click a button or press any key, then we do some background functionality based on this event. But for server software, we might have to wait for some incoming request and respond according with the request which usually means event. That is, there are two things that are involved; one is sending the event and another one is receiving the event. This means event sender activates the events whereas the receiver can handle it. But to handle the events means to execute some sort of methods which is usually done by the event handler. As the event sender does not know which method will handle the event, you need the third party who could point the event handler. This is called delegate which acts as a reference of the handler. I am using here both the event and delegate.

However, in order to see the sample code for the article, you have to:

  1. Download the sample ZIP file
  2. Browse to it and unzip the contents somewhere
  3. Go to Visual Studio and open the project

Background

When I was assigned to develop server software for the first time, I was surprised and spent my enough valuable time to make a decision which types of application should I start, should it be a console application or Winforms application. That time, I didn’t have much idea about multi-threading and other related issues. So I decided to start it in Winform application and finished it in due time perfectly. When it is deployed to the testing server, I am afraid to say that just after 30 min of its running, it gets freezed up. I am shocked and then tried to find out the problems and, solutions according that. This is what makes me show you how to develop a simple server application. This time I have developed it only for copying file from one directory to other directory. But by using this idea, you can develop any server software. This is only for beginners who wants to start developing this type of software. Yes of course by using the latest technology, we could develop a high level of server software but I am not going in this side so far but will be in the near future.

How It Works

We, the developers, always try to look into the performance when we develop an application. Is there any developer who wants his application to freeze or smash? But what are the steps a developer should yield to keep it all smooth going. When I used to develop this application, I saw whenever I attempt to copy files from one directory to other it includes CPU as well as hard drive. The major fallback of it is to limit a user to execute one task at a time. So how do we deal with application freezing and smashing?

By using threads through which we can handle all the jobs simultaneously under one main application thread. You can perform smaller operations with the help of threading class; instead I prefer using Background Worker class to implement to perform all my heavy duty operations. Background Worker is used to execute long running operations on a separate thread, support cancellation, progress reporting and marshalling results back to the UI thread. As I have offered the smooth UI which shows the operation details and at the same time the operation will continue in the background, I choose this one to use. If you want to know in details about the Background Worker, you can read this article.

The main mechanism is that when the user clicks the start button, it issues the event OnCopyStarted and the event handler is responsible for Copying data while at the same time OnUIChanged was getting issued and do some enable/disable UI Controls, when we click stop button, it issued the OnCopyStoppedEvent and at the same time it checks the Background worker’s working status does Background worker finish/Cancel its task or not. If not, it pops up the dialog window for a moment and waits for Background worker to be free, once the Backgroundworker gets free, the Dialogue will automatically dispose. Here I have used one way binding. So any changes in property value will reflect to the UI but changing the UI will not reflect on the properties.

Using the Code

First, please have a look at the Entities that I have used here:

//-----------------------------------------------------------------------
// <copyright file="MyFileSystemEntities.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------
namespace FileSystem.Replication.Server.Entities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// Properties of File System
    /// </summary>
    /// <remarks>This Class will use for submitting the
    /// Filesystem Properties in a object</remarks>
    public class MyFileSystemEntities
    {
        /// <summary>
        /// Gets or sets the copy to.
        /// </summary>
        /// <value>The copy to.</value>
        /// <remarks>The actual path where we want to COpy to</remarks>
        public string CopyTo{get;set;}

        /// <summary>
        /// Gets or sets the copy from.
        /// </summary>
        /// <value>The copy from.</value>
        /// <remarks>The actual path where from we want to copy</remarks>
        public string CopyFrom { get; set; }

        /// <summary>
        /// Gets or sets the messages.
        /// </summary>
        /// <value>The messages.</value>
        /// <remarks>The messages contain any messages
        /// or error manages related to the operation</remarks>
        public string Messages { get; set; }
    }
}

In this above code, the CopyTo holds the full path of directory to where we want to copy while CopyFrom holds the full path of directory from where we want to copy. The message holds the custom message or any error message to display in the window.

//-----------------------------------------------------------------------
// <copyright file="UIEntities.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------
namespace FileSystem.Replication.Server.Entities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// Properties for maintain UI
    /// </summary>
    public class UIEntities
    {
        /// <summary>
        /// Initializes a new instance of the UIEntities class.
        /// </summary>
        /// <remarks>it needs to create the UI Objects</remarks>
        public UIEntities() 
        { 
        }
        
        /// <summary>
        /// Gets or sets a value indicating whether [enable TXT copy from].
        /// </summary>
        /// <value><c>true</c> if [enable TXT copy from];
        /// otherwise, <c>false</c>.</value>
        /// <remarks>The text box Will be Enable or Disable
        /// based on the value of this property</remarks>
        public bool EnableTxtCopyFrom { get; set; }
        
        /// <summary>
        /// Gets or sets a value indicating whether [enable TXT copy to].
        /// </summary>
        /// <value><c>true</c> if [enable TXT copy to];
        /// otherwise, <c>false</c>.</value>
        /// <remarks>The text box Will be Enable or Disable based
        /// on the value of this property</remarks>
        public bool EnableTxtCopyTo { get; set; }
        
        /// <summary>
        /// Gets or sets a value indicating whether [enable BTN start].
        /// </summary>
        /// <value><c>true</c> if [enable BTN start];
        /// otherwise, <c>false</c>.</value>
        /// <remarks>The button Will be Enable or Disable
        /// based on the value of this property</remarks>
        public bool EnableBtnStart { get; set; }
        
        /// <summary>
        /// Gets or sets a value indicating whether [enable BTN stop].
        /// </summary>
        /// <value><c>true</c> if [enable BTN stop];
        /// otherwise, <c>false</c>.</value>
        /// <remarks>The button Will be Enable or Disable
        /// based on the value of this property</remarks>
        public bool EnableBtnStop { get; set; }
        
        /// <summary>
        /// Gets or sets a value indicating whether [enable BTN close].
        /// </summary>
        /// <value><c>true</c> if [enable BTN close];
        /// otherwise, <c>false</c>.</value>
        /// <remarks>The button Will be Enable or Disable
        /// based on the value of this property</remarks>
        public bool EnableBtnClose { get; set; }
        
        /// <summary>
        /// Gets or sets a value indicating whether [enable BTN copy from].
        /// </summary>
        /// <value><c>true</c> if [enable BTN copy from];
        /// otherwise, <c>false</c>.</value>
        /// <remarks>The button Will be Enable or Disable
        /// based on the value of this property</remarks>
        public bool EnableBtnCopyFrom { get; set; }
        
        /// <summary>
        /// Gets or sets a value indicating whether [enable BTN copy to].
        /// </summary>
        /// <value><c>true</c> if [enable BTN copy to];
        /// otherwise, <c>false</c>.</value>
        /// <remarks>The button Will be Enable or Disable based
        /// on the value of this property</remarks>
        public bool EnableBtnCopyTo { get; set; }
    }
}

The properties of the above class directly bind to the fields of the FrmMain.cs. As an example EnableTxtCopyFrom is bind to the TxtCopyform text box. This is something like this if the value of EnableTxtCopyFrom is true then the text box TxtCopyForm will be enabled and also will be disabled if it false. That is, it shows one way binding. And the property value has been changed when an event getting executed which needs to reflect to the UI.

Second, you also need to have a look on the custom event arguments that i have used here

//-----------------------------------------------------------------------
// <copyright file="MyFileSystemEventArgs.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------
namespace FileSystem.Replication.Server.MyEventArguments
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using FileSystem.Replication.Server.Entities;

    /// <summary>
    /// Define the properties for Custom Event Arguments
    /// </summary>
    public class MyFileSystemEventArgs : EventArgs
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="MyFileSystemEventArgs"/> class.
        /// </summary>
        /// <param name="submittedEntities">The submitted entities.</param>
        public MyFileSystemEventArgs(MyFileSystemEntities submittedEntities)
            : base()
        {
            this.MyCurrentFileSystemEntity = submittedEntities;
        }

        /// <summary>
        /// Gets or sets my current file system entity.
        /// </summary>
        /// <value>My current file system entity.</value>
        public MyFileSystemEntities MyCurrentFileSystemEntity { get; set; }
    }
}

The MyFileSystemEventArgs contains properties which is MyCurrentFileSystemEntity. MyCurrentFileSystemEntity is of MyFileSystemEntities that is; it contains all the properties of MyFileSystemEntities. I will show you where I have used this custom event args.

//-----------------------------------------------------------------------
// <copyright file="MyUIEventArgs.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------
namespace FileSystem.Replication.Server.MyEventArguments
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using FileSystem.Replication.Server.Entities;

    /// <summary>
    /// Property Definitions for Custom UI Event Arguments
    /// </summary>
    public class MyUIEventArgs : EventArgs
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="MyUIEventArgs"/> class.
        /// </summary>
        /// <param name="submittedEntities">The submitted entities.</param>
        public MyUIEventArgs(UIEntities submittedEntities)
            : base()
        {
            this.CurrentUIEntities = submittedEntities;
        }

        /// <summary>
        /// Gets or sets the current UI entities.
        /// </summary>
        /// <value>The current UI entities.</value>
        public UIEntities CurrentUIEntities { get; set; }
    }
}

Like MyFileSystemEventArgs, MyUIEventArgs also has an extra property CurrentUIEntities of UIEntities. I have already discussed about the MyFileSystemEventArgs and UIEntities.

Now come to the Delegate portion:

//-----------------------------------------------------------------------
// <copyright file="MyDelegates.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------
namespace FileSystem.Replication.Server.Delegates
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using FileSystem.Replication.Server.MyEventArguments;

    /// <summary>
    /// Declare My delegates
    /// </summary>
    /// <remarks></remarks>
    public class MyDelegates
    {
        /// <summary>
        /// This delegate can point to any method,taking two parameter 
        /// without returnnig anuthing
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="FileSystem.Replication.
        ///  Server.MyEventArguments.MyFileSystemEventArgs"/>
        /// instance containing the event data.</param>
        /// <remarks>Specially we will this for Copying file/directory</remarks>
        public delegate void CopyStartedEventHandler
            (object sender, MyFileSystemEventArgs e);
        
        /// <summary>
        /// This delegate can point to any method,taking two parameter 
        /// without returnnig anuthing
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see
        /// cref="System.EventArgs"/> instance
        /// containing the event data.</param>
        /// <remarks>We will use this for checking the background worker is free or not
        /// </remarks>
        public delegate void BackgroundWorkerCheckedEventHandler
				(object sender, EventArgs e);
        
        /// <summary>
        /// This delegate can point to any method,taking two parameter without 
        /// returning nothing
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="FileSystem.Replication.
        ///   Server.MyEventArguments.MyUIEventArgs"/> instance containing the event data.
        /// </param>
        /// <remarks>We will use this specilly to handle the UI Changes</remarks>
        public delegate void UIChangedEventHandler(object sender, MyUIEventArgs e);

        /// <summary>
        /// This delegate can point to any method,taking two parameter without 
        /// returning nothing
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/>
        /// instance containing the event data.</param>
        /// <remarks>We will use this to stop the file copying operation 
        /// for a instance</remarks>
        public delegate void CopyStoppedEventHandler(object sender, EventArgs e);    
    }
}

Okay, so the first thing I have done in this class is to declare delegates. There are four delegates which are used for four specific tasks. For example:

public delegate void CopyStartedEventHandler(object sender, MyFileSystemEventArgs e); 

The delegate defines the parameters sent to the event handlers. Thus any class that wants to handle this event must have a handler method which has the same return type and argument list as this delegate. Here as you can see, the first parameter is an object and the second parameter is my custom event arguments MyFileSystemEventArgs which has been discussed earlier. As its name is CopyStartedEventHandler, we could say that this delegate will use to make the reference of the method whose task is to perform Copy Operation.

Next come to the interface section:

//-----------------------------------------------------------------------
// <copyright file="IController.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------

namespace FileSystem.Replication.Server.Interfaces
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using FileSystem.Replication.Server.Entities;

    /// <summary>
    /// All Defnition related to Controller
    /// </summary>
    public interface IController
    {
        /// <summary>
        /// Gets or sets the background worker.
        /// </summary>
        /// <value>The background worker.</value>
        BackgroundWorker BackgroundWorker { get; set; }
        
        /// <summary>
        /// Does the copy.
        /// </summary>
        /// <param name="arguments">The arguments.</param>
        /// <param name="e">The <see
        /// cref="System.ComponentModel.DoWorkEventArgs"/>
        /// instance containing the event data.</param>
        void DoCopy(MyFileSystemEntities arguments, DoWorkEventArgs e);
    }
}

This IController interface defines the methods and properties of Controller Class. What the controller class does will be explained later on, especially when I will discuss about the controller class. Here, Background Worker is used to do the tasks simultaneously whereas DoCopy is used for Copy Operation.

//-----------------------------------------------------------------------
// <copyright file="IEvent.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------

namespace FileSystem.Replication.Server.Interfaces
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using FileSystem.Replication.Server.MyEventArguments;

    /// <summary>
    /// All Definition Related to Event handler
    /// </summary>
    public interface IEvent
    {
        /// <summary>
        /// Occurs when [copy started].
        /// </summary>
        event FileSystem.Replication.Server.Delegates.
        MyDelegates.CopyStartedEventHandler CopyStarted;
        
        /// <summary>
        /// Occurs when [copy stopped].
        /// </summary>
        event FileSystem.Replication.Server.Delegates.
        MyDelegates.CopyStoppedEventHandler CopyStopped;
        
        /// <summary>
        /// Occurs when [UI changed].
        /// </summary>
        event FileSystem.Replication.Server.Delegates.
        MyDelegates.UIChangedEventHandler UIChanged;
        
        /// <summary>
        /// Occurs when [background worker checked].
        /// </summary>
        event FileSystem.Replication.Server.Delegates.
        MyDelegates.BackgroundWorkerCheckedEventHandler BackgroundWorkerChecked;
        
        /// <summary>
        /// Raises the <see cref="E:BackgroundWorkerChecked"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        void OnBackgroundWorkerChecked(EventArgs e);
        
        /// <summary>
        /// Raises the <see cref="E:UIChanged"/> event.
        /// </summary>
        /// <param name="e">The 
        /// <see cref="FileSystem.Replication.Server.MyEventArguments.MyUIEventArgs"/> 
        /// instance containing the event data.</param>
        void OnUIChanged(MyUIEventArgs e);
        
        /// <summary>
        /// Raises the <see cref="E:FileCopyStopped"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        void OnFileCopyStopped(EventArgs e);
        
        /// <summary>
        /// Raises the <see cref="E:CopyStarted"/> event.
        /// </summary>
        /// <param name="e">The 
        /// <see cref="FileSystem.Replication.Server.MyEventArguments.
        /// MyFileSystemEventArgs"/> instance containing the event data.</param>
        void OnCopyStarted(MyFileSystemEventArgs e);
    }
}

This IEvent interface contains the signature of all custom events that are used in the project. You might split up it in two more interfaces depending on the modules. It also contains the signature of the methods that will be used to invoke the events. Here CopyStarted and CopyStopped is used to start and stop the Copy Operation while UIChanged is used to change the UI. OnCopyStarted is responsible for notifying receivers that the event CopyStarted occurred. In the same way, OnFileCopyStoped and OnUIChanged is responsible for notifying receivers that the event CopyStoped and UIChanged occurred.

//-----------------------------------------------------------------------
// <copyright file="ILogger.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------

namespace FileSystem.Replication.Server.Interfaces
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// All Definition related to FrmMain
    /// </summary>
    public interface ILogger
    {
        /// <summary>
        /// Gets or sets a value indicating whether this instance is 
        /// background worker free.
        /// </summary>
        /// <value><c>true</c> if this instance is background worker free; 
        /// otherwise, <c>false</c>.</value>
        bool IsBackgroundWorkerFree { get; set; }

        /// <summary>
        /// Gets or sets the waiting dialogue.
        /// </summary>
        /// <value>The waiting dialogue.</value>
        WaitingDialogue WaitingDialog { get; set; }

        /// <summary>
        /// Logs the specified submitted MSG.
        /// </summary>
        /// <param name="submittedMsg">The submitted MSG.</param>
        void Log(string submittedMsg);

        /// <summary>
        /// Logs the M.
        /// </summary>
        /// <param name="submttedMethodName">Name of the submtted method.</param>
        /// <param name="submittedMsg">The submitted MSG.</param>
        void LogM(string submttedMethodName,string submittedMsg);       
    }
}

This ILogger interface defines the methods and properties which are used for logging purposes. Here Log and LogM has been used to log the current progress, IsBackgroundWorkerFree has been used to check the current Background Worker status, is it free or not. This is especially needed if we are on the stage of copying a large file. Say, the BackgroundWorker is busy now to copy the file and have also been done half of its work, at this time if we want to stop the copying file the BackgroundWorker needs few times to cancel its operation. In this time period, I just display a busy dialog which usually guides you to wait for some moment. For doing this, I have used here a modal dialog which is WaitingDialog.

//-----------------------------------------------------------------------
// <copyright file="IMasterServices.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------

namespace FileSystem.Replication.Server.Interfaces
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using FileSystem.Replication.Server.Entities;

    /// <summary>
    /// All Definition related to MasterServices
    /// </summary>
    public interface IMasterServices
    {
        /// <summary>
        /// Copies the file.
        /// </summary>
        /// <param name="submittedEntities">The submitted entities.</param>
        /// <returns>if Succed return true otherwise false</returns>
        bool CopyFile(MyFileSystemEntities submittedEntities);

        /// <summary>
        /// Copies the directory.
        /// </summary>
        /// <param name="submittedEntities">The submitted entities.</param>
        /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> 
        /// instance containing the event data.</param>
        /// <returns>if Succed return true otherwise false</returns>
        bool CopyDirectory(MyFileSystemEntities submittedEntities, DoWorkEventArgs e);
    }
}

The IMasterServices which has defined the signature of MasterServices.CopyFile is used to copy file file whereas CopyDirectory is used to Copy directory from one place to another.

Now Come to the Implementation Stage

//-----------------------------------------------------------------------
// <copyright file="MyEventHandler.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------
namespace FileSystem.Replication.Server.Implementation
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using FileSystem.Replication.Server.Entities;
    using FileSystem.Replication.Server.Interfaces;
    using FileSystem.Replication.Server.MyEventArguments;
    using MyServer = FileSystem.Replication.Server.Delegates.MyDelegates;

    /// <summary>
    /// Implementation logic for IEvent
    /// </summary>
    public class MyEventHandler : IEvent
    {        
        #region Variables
        /// <summary>
        /// Object for sysnchronizing the copy operation
        /// </summary>
        private static object syncLockCopyStarted = new object();

        /// <summary>
        /// Object for sysnchronizing the UI Changes
        /// </summary>
        private static object syncLockUIChanged = new object();

        /// <summary>
        /// Object for sysnchronizing the copy stop operation
        /// </summary>
        private static object syncLockCopyStopped = new object();

        /// <summary>
        /// Used for synchronizing background worker operation
        /// </summary>
        private static object syncLockBackgroundWorkerChecked = new object();

        /// <summary>
        /// Contain CopyStartedEventHandler
        /// </summary>
        private MyServer.CopyStartedEventHandler copyStarted;        

        /// <summary>
        /// Contain CopyStoppedEventHandler
        /// </summary>
        private MyServer.CopyStoppedEventHandler copyStopped;
        
        /// <summary>
        /// Contain BackgroundWorkerCheckedEventHandler
        /// </summary>
        private MyServer.BackgroundWorkerCheckedEventHandler backgroundWorkerChecked;
        
        /// <summary>
        /// contain UIChangedEventHandler
        /// </summary>
        private MyServer.UIChangedEventHandler uiChanged;
        #endregion

        #region COnstructor

        /// <summary>
        /// Initializes a new instance of the <see cref="MyEventHandler"/> class.
        /// </summary>
        public MyEventHandler()
        {
        }
        #endregion

        #region Events
        /// <summary>
        /// Occurs when [copy started].
        /// </summary>
        public event MyServer.CopyStartedEventHandler CopyStarted
        {
            add
            {
                lock (syncLockCopyStarted)
                {
                    this.copyStarted += value;
                }
            }

            remove
            {
                lock (syncLockCopyStarted)
                {
                    this.copyStarted -= value;
                }
            }
        }

        /// <summary>
        /// Occurs when [copy stopped].
        /// </summary>
        public event MyServer.CopyStoppedEventHandler CopyStopped
        {
            add
            {
                lock (syncLockCopyStopped)
                {
                    this.copyStopped += value;
                }
            }

            remove
            {
                lock (syncLockCopyStopped)
                {
                    this.copyStopped -= value;
                }
            }
        }

        /// <summary>
        /// Occurs when [UI changed].
        /// </summary>
        public event MyServer.UIChangedEventHandler UIChanged
        {
            add
            {
                lock (syncLockUIChanged)
                {
                    this.uiChanged += value;
                }
            }

            remove
            {
                lock (syncLockUIChanged)
                {
                    this.uiChanged -= value;
                }
            }
        }

        /// <summary>
        /// Occurs when [background worker checked].
        /// </summary>
        public event MyServer.BackgroundWorkerCheckedEventHandler BackgroundWorkerChecked
        {
            add
            {
                lock (syncLockBackgroundWorkerChecked)
                {
                    this.backgroundWorkerChecked += value;
                }
            }

            remove
            {
                lock (syncLockBackgroundWorkerChecked)
                {
                    this.backgroundWorkerChecked -= value;
                }
            }
        }
        #endregion
       
        #region OnCopyStarted
        /// <summary>
        /// Raises the <see cref="E:CopyStarted"/> event.
        /// </summary>
        /// <param name="e">The 
        /// <see cref="FileSystem.Replication.Server.MyEventArguments.
        /// MyFileSystemEventArgs"/> instance containing the event data.</param>
        public void OnCopyStarted(MyFileSystemEventArgs e)
        {
            MyServer.CopyStartedEventHandler handler;
            
            lock (syncLockCopyStarted)
            {
                handler = this.copyStarted;
            }

            if (handler != null)
            {
                handler(this, e);
            }
        }
        #endregion

        #region OnFileCopyStopped
        /// <summary>
        /// Raises the <see cref="E:FileCopyStopped"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        public void OnFileCopyStopped(EventArgs e)
        {
            MyServer.CopyStoppedEventHandler handler;

            lock (syncLockCopyStopped)
            {
                handler = this.copyStopped;
            }

            if (handler != null)
            {
                handler(this, e);
            }
        }
        #endregion

        #region OnUIChanged
        /// <summary>
        /// Raises the <see cref="E:UIChanged"/> event.
        /// </summary>
        /// <param name="e">The <see cref="FileSystem.Replication.Server.
        /// MyEventArguments.MyUIEventArgs"/> instance containing the event data.</param>
        public void OnUIChanged(MyUIEventArgs e)
        {
            MyServer.UIChangedEventHandler handler;

            lock (syncLockUIChanged)
            {
                handler = this.uiChanged;
            }

            if (handler != null)
            {
                handler(this, e);
            }
        }
        #endregion

        #region OnBackgroundWorkerChecked
        /// <summary>
        /// Raises the <see cref="E:BackgroundWorkerChecked"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        public void OnBackgroundWorkerChecked(EventArgs e)
        {
            MyServer.BackgroundWorkerCheckedEventHandler handler;

            lock (syncLockBackgroundWorkerChecked)
            {
                handler = this.backgroundWorkerChecked;
            }

            if (handler != null)
            {
                handler(this, e);
            }
        }
        #endregion
    }
}

The MyEventHandler implements IEvent that contain the Events implementation and the method implementation to invoke those events. I need to explain something here:

public event MyServer.CopyStartedEventHandler CopyStarted
{
    add
    {
        lock (syncLockCopyStarted)
        {
            this.copyStarted += value;
        }
    }

    remove
    {
        lock (syncLockCopyStarted)
        {
            this.copyStarted -= value;
        }
    }
}

This above code shows that when the connector is about to execute a job, you can catch this event to perform monitoring work.

public void OnCopyStarted(MyFileSystemEventArgs e)
{
    MyServer.CopyStartedEventHandler handler;
    
    lock (syncLockCopyStarted)
    {
        handler = this.copyStarted;
    }

    if (handler != null)
    {
        handler(this, e);
    }
}

The above code shows the method that is responsible for notifying receivers that the event occurred.

//-----------------------------------------------------------------------
// <copyright file="Controller.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------
namespace FileSystem.Replication.Server.Implementation
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using FileSystem.Replication.Server.Entities;
    using FileSystem.Replication.Server.Implementation;
    using FileSystem.Replication.Server.Interfaces;
    using FileSystem.Replication.Server.MyEventArguments;

    /// <summary>
    /// Implentation all logic og IController
    /// </summary>
    public class Controller : IController
    {
        #region Variables        
        /// <summary>
        /// Contain ILogger
        /// </summary>
        private ILogger log = null;

        /// <summary>
        /// Contain IMasterServices
        /// </summary>
        private IMasterServices services = null;

        /// <summary>
        /// Contain IEvents
        /// </summary>
        private IEvent customEvent = null;        
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="Controller"/> class.
        /// </summary>
        /// <param name="submittedLog">The submitted log.</param>
        /// <param name="submittedCustomEvent">The submitted custom event.</param>
        public Controller(ILogger submittedLog, IEvent submittedCustomEvent)
        {
            try
            {
                this.log = submittedLog;
                this.customEvent = submittedCustomEvent;
                this.customEvent.CopyStarted += new FileSystem.Replication.Server.
            Delegates.MyDelegates.CopyStartedEventHandler
            (this.Controller_FileCopyStarted);
                this.customEvent.CopyStopped += new FileSystem.Replication.Server.
            Delegates.MyDelegates.CopyStoppedEventHandler
            (this.Controller_FileCopyStopped);
                this.customEvent.BackgroundWorkerChecked += 
            new FileSystem.Replication.Server.Delegates.MyDelegates.
            BackgroundWorkerCheckedEventHandler
            (this.Controller_BackgroundWorkerChecked);
                this.BackgroundWorker = new System.ComponentModel.BackgroundWorker();
                this.BackgroundWorker.WorkerSupportsCancellation = true;
                this.BackgroundWorker.DoWork += 
            new System.ComponentModel.DoWorkEventHandler
            (this.BackgroundWorker_DoWork);
                this.BackgroundWorker.RunWorkerCompleted += 
            new RunWorkerCompletedEventHandler
                (this.BackgroundWorker_RunWorkerCompleted);
                this.services = new MasterServices(this.log, this.BackgroundWorker);
            }
            catch (Exception oEx)
            {
                this.log.LogM("Controller", oEx.ToString());
            }
        }
        #endregion

        #region properties
        /// <summary>
        /// Gets or sets the background worker.
        /// </summary>
        /// <value>The background worker.</value>
        public BackgroundWorker BackgroundWorker { get; set; }
        #endregion

        #region Controller_BackgroundWorkerChecked
        /// <summary>
        /// Handles the BackgroundWorkerChecked event of the Controller control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        private void Controller_BackgroundWorkerChecked(object sender, EventArgs e)
        {
            if (this.log.IsBackgroundWorkerFree == true)
            {
                this.log.WaitingDialog.Dispose();
            }
        }
        #endregion

        #region BackgroundWorker_DoWork
        /// <summary>
        /// Handles the DoWork event of the BackgroundWorker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> 
        /// instance containing the event data.</param>
        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                System.ComponentModel.BackgroundWorker bw = 
            sender as System.ComponentModel.BackgroundWorker;

                UIEntities ui = new UIEntities()
                {
                    EnableBtnClose = true,
                    EnableBtnCopyFrom = false,
                    EnableBtnCopyTo = false,
                    EnableBtnStop = true,
                    EnableBtnStart = false,
                    EnableTxtCopyFrom = false,
                    EnableTxtCopyTo = false
                };
                MyUIEventArgs uiArgs = new MyUIEventArgs(ui);

                this.customEvent.OnUIChanged(uiArgs);

                MyFileSystemEntities arguments = e.Argument as MyFileSystemEntities;
                this.log.Log("Start Copying \n");
                this.DoCopy(arguments, e);
            }
            catch (Exception oEx)
            {
                this.log.LogM("BackgroundWorker_DoWork", oEx.ToString());
            }
        }
        #endregion

        #region DoCopy
        /// <summary>
        /// Does the copy.
        /// </summary>
        /// <param name="arguments">The arguments.</param>
        /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> 
        /// instance containing the event data.</param>
        public void DoCopy(MyFileSystemEntities arguments, DoWorkEventArgs e)
        {
            if (arguments == null)
            {
                throw new ArgumentNullException();
            }
            else
            {
                if (!string.IsNullOrEmpty(arguments.CopyFrom))
                {
                    if (Directory.Exists(arguments.CopyFrom))
                    {
                        this.services.CopyDirectory(arguments, e);
                    }
                    else if (File.Exists(arguments.CopyFrom))
                    {
                        this.services.CopyFile(arguments);
                    }
                }
            }
        }
        #endregion

        #region BackgroundWorker_RunWorkerCompleted
        /// <summary>
        /// Handles the RunWorkerCompleted event of the backgroundWorker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.
        /// RunWorkerCompletedEventArgs"/> instance containing the event data.</param>
        private void BackgroundWorker_RunWorkerCompleted
        (object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                if (e.Cancelled)
                {
                    UIEntities ui = new UIEntities()
                    {
                        EnableBtnClose = true,
                        EnableBtnCopyFrom = true,
                        EnableBtnCopyTo = true,
                        EnableBtnStop = false,
                        EnableBtnStart = true,
                        EnableTxtCopyFrom = true,
                        EnableTxtCopyTo = true
                    };

                    MyUIEventArgs uiArgs = new MyUIEventArgs(ui);

                    this.customEvent.OnUIChanged(uiArgs);
                    this.log.Log("User cancels the Operation \n");
                    this.log.IsBackgroundWorkerFree = true;
                }
                else
                {
                    UIEntities ui = new UIEntities()
                    {
                        EnableBtnClose = true,
                        EnableBtnCopyFrom = true,
                        EnableBtnCopyTo = true,
                        EnableBtnStop = false,
                        EnableBtnStart = true,
                        EnableTxtCopyFrom = true,
                        EnableTxtCopyTo = true
                    };

                    MyUIEventArgs uiArgs = new MyUIEventArgs(ui);

                    this.customEvent.OnUIChanged(uiArgs);
                    this.log.Log("Opearation completed \n");
                    this.log.IsBackgroundWorkerFree = true;
                }
            }
            catch (Exception oEx)
            {
                this.log.LogM("backgroundWorker_RunWorkerCompleted", oEx.ToString());
            }
        }
#endregion

        #region Controller_FileCopyStopped
        /// <summary>
        /// Handles the FileCopyStopped event of the Controller control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        private void Controller_FileCopyStopped(object sender, EventArgs e)
        {
            try
            {
                this.BackgroundWorker.CancelAsync();
            }
            catch (Exception oEx)
            {
                this.log.LogM("Controller_FileCopyStopped", oEx.ToString());
            }
        }
        #endregion

        #region Controller_FileCopyStarted
        /// <summary>
        /// Handles the FileCopyStarted event of the Controller control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="FileSystem.Replication.Server.
        /// MyEventArguments.MyFileSystemEventArgs"/> instance containing the event data.
        /// </param>
        private void Controller_FileCopyStarted(object sender, MyFileSystemEventArgs e)
        {
            try
            {
                MyFileSystemEntities entities = e.MyCurrentFileSystemEntity;

                if (entities != null && !string.IsNullOrEmpty(entities.CopyFrom) && 
                !string.IsNullOrEmpty(entities.CopyTo))
                {
                    this.BackgroundWorker.RunWorkerAsync(entities);
                }
            }
            catch (Exception oEx)
            {
                this.log.LogM("Controller_FileCopyStarted", oEx.ToString());
            }
        }
        #endregion
    }
}   

The Controller class implements the IController interface and when any request comes from the front end, it will decide back ground working process. As an example, when file copy event is fired the Controller class handles it, call the Background Worker RunWorkerAsync() which usually means that to start execution of background worker copy operation. If any request comes to stop copy operation, the controller call Background Worker CancelAsync() which usually means submitting a request to terminate the pending background operation. If it successfully completes its task, then it fires the BackgroundWorker RunWorkerCompleted and RunWorkerCompletedEventArgs.Cancelled will be false and then the background worker will be free. If it cancels its task like as if we Click the stop button to stop the copy operation, it also fires the Background Worker RunWorkerCompleted but in this case RunWorkerCompletedEventArgs.Cancelled should be true and the background worker getting free. When it succeeds or cancels its operation that is, when it reaches the Completed state, it executes the UIChanged Event to change the UI according to this.

//-----------------------------------------------------------------------
// <copyright file="MasterServices.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------
namespace FileSystem.Replication.Server.Implementation
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.IO;
    using System.Linq;
    using System.Text;
    using FileSystem.Replication.Server.Entities;
    using FileSystem.Replication.Server.Interfaces;

    /// <summary>
    /// Implementaion logic for IMasterservices
    /// </summary>
    public class MasterServices : IMasterServices
    {
        #region Variables
        /// <summary>
        /// Contain Logger
        /// </summary>
        private ILogger log = null;

        /// <summary>
        /// Contain BackgroundWorker
        /// </summary>
        private BackgroundWorker backgroundWorker = null;
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="MasterServices"/> class.
        /// </summary>
        /// <param name="submittedLog">The submitted log.</param>
        /// <param name="submittedBackgroundWorker">The submitted background worker.
        /// </param>
        public MasterServices(ILogger submittedLog, 
		BackgroundWorker submittedBackgroundWorker)
        {
            this.log = submittedLog;
            this.backgroundWorker = submittedBackgroundWorker;
        }
        #endregion

        #region IMasterServices Members
        /// <summary>
        /// Copies the file.
        /// </summary>
        /// <param name="submittedEntities">The submitted entities.</param>
        /// <returns>true if Succeed otherwiae false</returns>
        public bool CopyFile(MyFileSystemEntities submittedEntities)
        {
            if (submittedEntities == null)
            {
                throw new ArgumentNullException();
            }

            if (string.IsNullOrEmpty(submittedEntities.CopyFrom))
            {
                throw new ArgumentNullException();
            }
            else if (string.IsNullOrEmpty(submittedEntities.CopyTo))
            {
                throw new ArgumentNullException();
            }
            else
            {
                try
                {
                    if (File.Exists(submittedEntities.CopyFrom))
                    {
                        this.log.Log("Coping  file : \n\n Source :" + 
			submittedEntities.CopyFrom + "\n Destination :" + 
			submittedEntities.CopyTo + "\n");
                        File.Copy(submittedEntities.CopyFrom, 
				submittedEntities.CopyTo, true);
                        return true;
                    }

                    return false;
                }
                catch (Exception oEx)
                {
                    this.log.LogM("CopyFile", oEx.ToString());
                    return false;
                }
            }
        }
#endregion

        #region CopyDirectory
        /// <summary>
        /// Copies the directory.
        /// </summary>
        /// <param name="submittedEntities">The submitted entities.</param>
        /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> 
        /// instance containing the event data.</param>
        /// <returns>return true if succeeded otherwise false</returns>
        public bool CopyDirectory
		(MyFileSystemEntities submittedEntities, DoWorkEventArgs e)
        {
            if (submittedEntities == null)
            {
                throw new ArgumentNullException();
            }
            else if (string.IsNullOrEmpty(submittedEntities.CopyFrom))
            {
                throw new ArgumentNullException();
            }
            else if (string.IsNullOrEmpty(submittedEntities.CopyTo))
            {
                throw new ArgumentNullException();
            }
            else
            {
                try
                {
                    DirectoryInfo sourceDir = 
			new DirectoryInfo(submittedEntities.CopyFrom);

                    DirectoryInfo destDir = new DirectoryInfo(submittedEntities.CopyTo);

                        if (!destDir.Exists)
                        {
                            destDir.Create();
                        }

                        foreach (FileInfo childFile in sourceDir.GetFiles())
                        {
                            if (this.backgroundWorker != null)
                            {
                                if (this.backgroundWorker.CancellationPending == true)
                                {
                                    e.Cancel = true;
                                    break;
                                }
                                else
                                {
                                    this.log.Log("Coping  file : \n\n Source :" + 
					childFile.FullName + "\n Destination :" + 
					Path.Combine(destDir.FullName, 
					childFile.Name) + "\n");

                                    childFile.CopyTo(Path.Combine
				(destDir.FullName, childFile.Name), true);
                                }
                            }
                        }

                        foreach (DirectoryInfo subDir in sourceDir.GetDirectories())
                        {
                            if (this.backgroundWorker != null)
                            {
                                if (this.backgroundWorker.CancellationPending == true)
                                {
                                    e.Cancel = true;
                                    break;
                                }
                                else
                                {
                                    if (!subDir.Exists)
                                    {
                                        this.log.Log("Directory Created :" + 
							subDir + "\n");

                                        subDir.Create();
                                    }

                                    bool retVal;

                                    retVal = this.CopyDirectory
				(new MyFileSystemEntities() 
				{ CopyFrom = subDir.FullName, CopyTo = 
				Path.Combine(destDir.FullName, subDir.Name) }, e);
                                    
                                    if (!retVal)
                                    {
                                        return false;
                                    }
                                }
                            }
                        }

                        return true;                   
                }
                catch (Exception oEx)
                {
                    this.log.LogM("CopyDirectory", oEx.ToString());
                    return false;
                }
            }
        }
        #endregion
    }
}

MasterServices implements IMasterService. We have seen that in the method CopyDirectory, there are two parameters one is of MyFileSystemEntities another one is of DoWorkEventArgs, this is an event which is used for background worker to start its task. As I have used here a single operation, I have maintained the background worker from the controller. If there is more than one controller for many operations, you might use different background work for different operations. You have seen that the function first does the sanity checking then it reads the full path of the source and destination directory. If the destination directory does not exist, it then creates it. In foreach loop, it gets all the files and directories of source directories and also listens if anyone clicks the Stop button. That is if anyone clicks the stop button, the Background Worker Cancellation pending will be true and once it’s set to true, it sets DoWorkEventsArgs.Cancel is true which usually fires the Background Worker RunWorkerCompleted Event means that it is interrupted to stop its working. Once Background Worker RunWorkerCompleted gets executed, then it will be free to do another task.

//-----------------------------------------------------------------------
// <copyright file="FrmMain.cs" company="Self">
//  Copyright (c) Md. Rashim Uddin . All rights reserved.
// </copyright>
// <author>Md. Rashim Uddin</author>
// <email>rashimiiuc@yahoo.com</email>
//-----------------------------------------------------------------------
namespace FileSystem.Replication.Server
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using FileSystem.Replication.Server.Entities;
    using FileSystem.Replication.Server.Implementation;
    using FileSystem.Replication.Server.Interfaces;
    using FileSystem.Replication.Server.MyEventArguments;

    /// <summary>
    /// Implementation logic for ILOgger
    /// </summary>
    public partial class FrmMain : Form, ILogger
    {
        #region Variables
        /// <summary>
        /// Contain Controller
        /// </summary>
        private IController controller = null;

        /// <summary>
        /// Contain BackgroundWorker
        /// </summary>
        private bool isBackgroundWorkerFree = false;

        /// <summary>
        /// Contain IEvent
        /// </summary>
        private IEvent myEvent = null;
        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="FrmMain"/> class.
        /// </summary>
        public FrmMain()
        {                   
            InitializeComponent();
            this.myEvent = new MyEventHandler();
            this.controller = new Controller(this, this.myEvent);
            this.myEvent.UIChanged += 
		new FileSystem.Replication.Server.Delegates.MyDelegates.
		UIChangedEventHandler(this.Controller_UIChanged);
        }
        #region properties
        /// <summary>
        /// Gets or sets the waiting dialogue.
        /// </summary>
        /// <value>The waiting dialogue.</value>
        public WaitingDialogue WaitingDialog { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is 
        /// background worker free.
        /// </summary>
        /// <value><c>true</c> if this instance is background worker free; otherwise, 
        /// <c>false</c>.</value>
        public bool IsBackgroundWorkerFree
        {
            get
            {
                return this.isBackgroundWorkerFree;
            }

            set
            {
                this.isBackgroundWorkerFree = value;
                this.myEvent.OnBackgroundWorkerChecked(new EventArgs());
            }
        }
        #endregion

        #region ILogger Members
        /// <summary>
        /// Logs the specified submitted MSG.
        /// </summary>
        /// <param name="submittedMsg">The submitted MSG.</param>
        public void Log(string submittedMsg)
        {
            if (this != null && !string.IsNullOrEmpty(submittedMsg))
            {
                if (this.TxtLog != null)
                {
                    if (this.InvokeRequired)
                    {
                        this.BeginInvoke((MethodInvoker)delegate()
                        {
                            string logMsg = string.Format("[{0}] {1}\r\n", 
					DateTime.Now, submittedMsg);
                            this.TxtLog.AppendText(logMsg);
                            this.TxtLog.SelectionStart = this.TxtLog.TextLength;
                            this.TxtLog.ScrollToCaret();
                        });
                    }
                    else
                    {
                        string logMsg = string.Format("[{0}] {1}\r\n", 
					DateTime.Now, submittedMsg);
                        this.TxtLog.AppendText(logMsg);
                        this.TxtLog.SelectionStart = this.TxtLog.TextLength;
                        this.TxtLog.ScrollToCaret();
                    }
                }
            }
        }

        /// <summary>
        /// Logs the M.
        /// </summary>
        /// <param name="submttedMethodName">Name of the submtted method.</param>
        /// <param name="submittedMsg">The submitted MSG.</param>
        public void LogM(string submttedMethodName, string submittedMsg)
        {
            if (this != null && !string.IsNullOrEmpty(submittedMsg))
            {
                if (this.TxtLog != null)
                {
                    if (this.InvokeRequired)
                    {
                        this.BeginInvoke((MethodInvoker)delegate()
                        {
                            string logMsg = string.Format("[{0}][{1}] {2}\r\n", 
				DateTime.Now, submttedMethodName, submittedMsg);
                            this.TxtLog.AppendText(logMsg);
                            this.TxtLog.SelectionStart = this.TxtLog.TextLength;
                            this.TxtLog.ScrollToCaret();
                        });
                    }
                    else
                    {
                        string logMsg = string.Format("[{0}][{1}] {2}\r\n", 
				DateTime.Now, submttedMethodName, submittedMsg);
                        this.TxtLog.AppendText(logMsg);
                        this.TxtLog.SelectionStart = this.TxtLog.TextLength;
                        this.TxtLog.ScrollToCaret();
                    }
                }
            }
        }
        #endregion

        #region Controller_UIChanged
        /// <summary>
        /// Handles the UIChanged event of the Controller control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see
        /// cref="FileSystem.Replication.Server.MyEventArguments.MyUIEventArgs"/>
        /// instance containing the event data.</param>
        private void Controller_UIChanged(object sender, MyUIEventArgs e)
        {
            try
            {
                UIEntities entities = e.CurrentUIEntities;

                if (this.InvokeRequired)
                {
                    this.BeginInvoke((MethodInvoker)delegate
                    {
                        this.TxtCopyFrom.Enabled = entities.EnableTxtCopyFrom;
                        this.TxtCopyTo.Enabled = entities.EnableTxtCopyTo;
                        this.BtnStart.Enabled = entities.EnableBtnStart;
                        this.BtnStop.Enabled = entities.EnableBtnStop;
                        this.BtnClose.Enabled = entities.EnableBtnClose;
                        this.BtnCopyFrom.Enabled = entities.EnableBtnCopyFrom;
                        this.BtnCopyTo.Enabled = entities.EnableBtnCopyTo;
                    });
                }
                else
                {
                    this.TxtCopyFrom.Enabled = entities.EnableTxtCopyFrom;
                    this.TxtCopyTo.Enabled = entities.EnableTxtCopyTo;
                    this.BtnStart.Enabled = entities.EnableBtnStart;
                    this.BtnStop.Enabled = entities.EnableBtnStop;
                    this.BtnClose.Enabled = entities.EnableBtnClose;
                    this.BtnCopyFrom.Enabled = entities.EnableBtnCopyFrom;
                    this.BtnCopyTo.Enabled = entities.EnableBtnCopyTo;
                }
            }
            catch (Exception oEx)
            {
                this.LogM("Controller_UIChanged", oEx.ToString());
            }
        }
        #endregion

        #region BtnStart_Click
        /// <summary>
        /// Handles the Click event of the BtnStart control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        private void BtnStart_Click(object sender, EventArgs e)
        {
            try
            {
                TxtLog.Text = string.Empty;

                string copyTO = !string.IsNullOrEmpty(this.TxtCopyTo.Text) ? 
				this.TxtCopyTo.Text : string.Empty;
                string copyFrom = !string.IsNullOrEmpty(this.TxtCopyFrom.Text) ? 
				this.TxtCopyFrom.Text : string.Empty;

                if (!string.IsNullOrEmpty(copyFrom) && !string.IsNullOrEmpty(copyTO))
                {
                    MyFileSystemEventArgs args = new MyFileSystemEventArgs
			(new MyFileSystemEntities() { CopyFrom = copyFrom, 
			CopyTo = copyTO, Messages = string.Empty });
                    this.myEvent.OnCopyStarted(args);
                }
                else
                {
                    MessageBox.Show("Please Specify the 'Copy from' and 'Copy to'");
                }
            }
            catch (Exception oEx)
            {
                this.LogM("BtnStart_Click", oEx.ToString());
            }
        }
        #endregion

        #region BtnStop_Click
        /// <summary>
        /// Handles the Click event of the BtnStop control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
			instance containing the event data.</param>
        private void BtnStop_Click(object sender, EventArgs e)
        {
            try
            {
                this.WaitingDialog = new WaitingDialogue();

                this.myEvent.OnFileCopyStopped(e);

                if (this.controller.BackgroundWorker.IsBusy)
                {
                    this.WaitingDialog.ShowDialog();
                }
            }
            catch (Exception oEx)
            {
                this.LogM("BtnStop_Click", oEx.ToString());
            }
        }
        #endregion

        #region BtnClose_Click
        /// <summary>
        /// Handles the Click event of the BtnClose control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        ///instance containing the event data.</param>
        private void BtnClose_Click(object sender, EventArgs e)
        {
            if (!this.controller.BackgroundWorker.IsBusy)
            {
                Application.Exit();
            }
            else
            {
                MessageBox.Show("Server is running. Please stop it first");
            }
        }
        #endregion

        #region FrmMain_FormClosing
        /// <summary>
        /// Handles the FormClosing event of the FrmMain control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.FormClosingEventArgs"/> 
        /// instance containing the event data.</param>
        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                if (!this.controller.BackgroundWorker.IsBusy)
                {
                    Application.Exit();
                }
                else
                {
                    MessageBox.Show("Server is running. Please stop it first");
                    e.Cancel = true;
                }
            }
        }
        #endregion

        #region FrmMain_Load
        /// <summary>
        /// Handles the Load event of the FrmMain control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        private void FrmMain_Load(object sender, EventArgs e)
        {            
            UIEntities ui = new UIEntities()
            {
                EnableBtnClose = true,
                EnableBtnCopyFrom = true,
                EnableBtnCopyTo = true,
                EnableBtnStop = false,
                EnableBtnStart = true,
                EnableTxtCopyFrom = true,
                EnableTxtCopyTo = true
            };

            MyUIEventArgs uiArgs = new MyUIEventArgs(ui);
            this.myEvent.OnUIChanged(uiArgs);
        }
        #endregion        

        #region BtnCopyFrom_Click
        /// <summary>
        /// Handles the Click event of the BtnCopyFrom control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        private void BtnCopyFrom_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
            {
                folderDialog.ShowDialog();
                this.TxtCopyFrom.Text = folderDialog.SelectedPath.ToString();                
            }

            this.SetUpUIForStartOperation();
        }
        #endregion

        #region BtnCopyTo_Click
        /// <summary>
        /// Handles the Click event of the BtnCopyTo control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        private void BtnCopyTo_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
            {
                folderDialog.ShowDialog();
                this.TxtCopyTo.Text = folderDialog.SelectedPath.ToString();
            }

            this.SetUpUIForStartOperation();
        }
        #endregion

        #region SetUpUIForStartOperation
        /// <summary>
        /// Sets up UI for start operation.
        /// </summary>
        private void SetUpUIForStartOperation()
        {
            if (!string.IsNullOrEmpty(this.TxtCopyTo.Text) && 
   			!string.IsNullOrEmpty(this.TxtCopyFrom.Text))
            {
                if (this.IsItValidDirectory(this.TxtCopyFrom.Text) && 
			this.IsAnyParentDirectory(this.TxtCopyTo.Text))
                {
                    UIEntities ui = new UIEntities()
                    {
                        EnableBtnClose = true,
                        EnableBtnCopyFrom = true,
                        EnableBtnCopyTo = true,
                        EnableBtnStop = false,
                        EnableBtnStart = true,
                        EnableTxtCopyFrom = true,
                        EnableTxtCopyTo = true
                    };

                    MyUIEventArgs uiArgs = new MyUIEventArgs(ui);

                    this.myEvent.OnUIChanged(uiArgs);
                }
                else 
                {
                    MessageBox.Show("Please enter a valid directory path in 'Copy form'");
                }
            }
        }
        #endregion

        #region IsItValidDirectory
        /// <summary>
        /// Determines whether [is it valid directory] 
        /// [the specified submitted full path].
        /// </summary>
        /// <param name="submittedFullPath">The submitted full path.</param>
        /// <returns><c>true</c> if [is it valid directory] 
        /// [the specified submitted full path]; otherwise, <c>false</c>.</returns>
        private bool IsItValidDirectory(string submittedFullPath)
        {
            if (!string.IsNullOrEmpty(submittedFullPath))
            {
                return Directory.Exists(submittedFullPath);
            }

            return false;
        }
        #endregion

        #region IsAnyParentDirectory
        /// <summary>
        /// Determines whether [is any parent directory] 
        /// [the specified submitted full path].
        /// </summary>
        /// <param name="submittedFullPath">The submitted full path.</param>
        /// <returns><c>true</c> if [is any parent directory] 
        /// [the specified submitted full path]; otherwise, <c>false</c>.</returns>
        private bool IsAnyParentDirectory(string submittedFullPath)
        {
            if (!string.IsNullOrEmpty(submittedFullPath))
            {
                string parentPath = submittedFullPath.Trim
  				(' ', Path.DirectorySeparatorChar);
                parentPath = parentPath.LastIndexOf
			(Path.DirectorySeparatorChar) >

This class implements the ILogger and contains the IController, IMasterService, IEvent. When we click the button CopyFrom/CopyTo, it pops up Folder Browser to set the specific path. When we click Start button, it issues the event onCopyStarted whereas when we click the stop button, it issues the event onFileCopyStopped. It also maintains the log for all operations including if any exception occurred.

For better understanding, there is a need to clarify and explain the following methods:

public void Log(string submittedMsg)
{
    if (this != null && !string.IsNullOrEmpty(submittedMsg))
    {
        if (this.TxtLog != null)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke((MethodInvoker)delegate()
                {
                    string logMsg = string.Format("[{0}] {1}\r\n", 
				DateTime.Now, submittedMsg);
                    this.TxtLog.AppendText(logMsg);
                    this.TxtLog.SelectionStart = this.TxtLog.TextLength;
                    this.TxtLog.ScrollToCaret();
                });
            }
            else
            {
                string logMsg = string.Format("[{0}] {1}\r\n", 
				DateTime.Now, submittedMsg);
                this.TxtLog.AppendText(logMsg);
                this.TxtLog.SelectionStart = this.TxtLog.TextLength;
                this.TxtLog.ScrollToCaret();
            }
        }
    }
}

This function takes the submittedMessage as a parameter and this will display on the form. What it does actually is that it first checks the parameter, then checks that if there is any invocation required. If it requires, then I have used here MethodInvoker which is a delegate that can execute any method in managed code. Using this.BeginInvoke((MethodInvoker)delegate() ensures that the delegate is called on the GUI thread. This is a technique of avoiding code duplication when the same method can be called both from the GUI thread and other threads.

That's It

That's it for now, I hope this article and the result downloads inspire you enough to develop your own server software.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here