Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

FTP Activity for Windows Workflow Foundation

5.00/5 (5 votes)
18 Jul 2009CPOL1 min read 32.5K   352  
Custom activity for file operations over FTP folders.

Introduction

Windows Workflow Foundation, with its set of activities, provides an easy and visual way to build applications. But, what if the available activities are not suitable for our needs and we don't want to use a CodeActivity? Let's create a custom activity; below, you can find a very basic one for file operations over FTP.

Using the code

The FTP activity supports upload/delete/list of files from an FTP server. You can either add the project George.WWF.Activities.FTP to your solution, or add the activity to your toolbox (Tools-> Choose toolbox items) in order to use it.

CropperCapture_2_.jpg

Once dropped on the design windows, the activity will warn the user that the required properties are not set:

CropperCapture_1_.jpg

Validation is managed by the FTPActivityValidator class that inherits from ActivityValidator.

The custom class FTPActivityValidator can now be used to validate the activity class:

C#
[ActivityValidator(typeof(FTPActivityValidator))]
public partial class FTPActivity : System.Workflow.ComponentModel.Activity

We can now decide how we want to bind the properties; we can do it at design time:

CropperCapture_5_.jpg

or programmatically; maybe the values can come from a config file:

CropperCapture_4_.jpg

C#
private void initFTPActivity_ExecuteCode(object sender, EventArgs e)
{
    this.ftpActivity1_FTPServer1 = "10.20.100.65";
    this.ftpActivity1_FTPUserName1 = "Giorgio";
    ...
}

The activity is easily customizable, so support to other operations can be added extending the FTP core classes:

Here is the code for the FTP Manager:

C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

using System.Net;
using System.IO;

namespace George.WWF.Activities.FTP
{
    public enum OperationType
    {
        Upload = 0,
        Delete = 1 ,
        List = 2
    }

    public class FtpManager
    {
        #region Class members

        OperationType operation;
     
        //NetworkCredential networkCredentials;
        FtpEntity ftpEntity;  
        FtpWebRequest ftpWebRequest;
        Stream ftpStream;

        #endregion

        #region Members modifiers

        public OperationType Operation
        {
            get { return operation; }
        }
    
        #endregion


        public FtpManager(FtpEntity ftpEntity) 
        {
            this.ftpEntity = ftpEntity;
        }

        public bool CreateFtpFile(string file, string destinationFolder)
        {
            FtpWebRequest request = null;
            try
            {
                FileInfo fileInfo = new FileInfo(file);
                request = (FtpWebRequest)WebRequest.Create(string.Format("{0}/{1}/{2}", 
                           ftpEntity.FtpServer, destinationFolder, fileInfo.Name));
                request.Method = WebRequestMethods.Ftp.UploadFile;
                request.Credentials = new NetworkCredential(ftpEntity.Username, 
                                          ftpEntity.Password);
                //request.UsePassive=true;
                request.UseBinary=true;
                request.KeepAlive=false;
                request.ContentLength = fileInfo.Length;

                // The buffer size is set to 512k
                int buffLength = 512;
                byte[] buff = new byte[buffLength];
                int contentLen;

                // Opens a file stream (System.IO.FileStream) to read the file
                // to be uploaded
                FileStream fs = fileInfo.OpenRead();

                try
                {
                    // Stream to which the file to be upload is written
                    Stream strm = request.GetRequestStream();

                    // Read from the file stream 512k at a time
                    contentLen = fs.Read(buff, 0, buffLength);

                    // Till Stream content ends
                    while (contentLen != 0)
                    {
                        // Write Content from the file stream to the FTP Upload
                        // Stream
                        strm.Write(buff, 0, contentLen);
                        contentLen = fs.Read(buff, 0, buffLength);
                    }

                    // Close the file stream and the Request Stream
                    strm.Close();
                    fs.Close();
                    strm.Dispose();
                    fs.Dispose();

                }
                catch(Exception ex) 
                {
                    //LoggingHelper.Error(string.Format("Error while creating file " + 
                    //   "{0} on ftp {1} - Error : {2}", file.FileToManage.Name, 
                    //   ftpEntity.FtpServer,ex.Message));
                    return false; 
                }
              
            }
            catch
            {
                //LoggingHelper.Error(string.Format("Error while creating file " + 
                //   "{0} on ftp {1}", file.FileToManage.Name, ftpEntity.FtpServer));
                return false;
            }
            finally
            {
                //requestStream.Close();
                //response.Close();
            }

            return true;

        }

        public bool DeleteFtpFiles(string folder)
        {
            try
            {
                string[] directoryFiles = ListFtpFiles(folder);
                for (int i = 0; i < directoryFiles.Length; i++)
                {
                    if (!string.IsNullOrEmpty(directoryFiles[i]))
                        DeleteFtpFile(directoryFiles[i], folder);
                }
            }
            catch
            {
                //LoggingHelper.Error(string.Format("Error while deleting" + 
                //    " files on ftp {1}", ftpEntity.FtpServer));
                return false;
            }
            return true;
        }

        public string[] ListFtpFiles(string folder)
        {
            // Get the object used to communicate with the server.
            ftpWebRequest = (FtpWebRequest)WebRequest.Create(
              new Uri(string.Format("{0}/{1}", ftpEntity.FtpServer, folder)));
            this.operation = OperationType.List;
            ChooseOperationType();
            SettingFtpManager();


            FtpWebResponse ftpWebResponse = 
               (FtpWebResponse)ftpWebRequest.GetResponse();

            ftpStream = null;
            ftpStream = ftpWebResponse.GetResponseStream();
            StreamReader reader = new StreamReader(ftpStream);
            string[] directoryFiles = Regex.Split(
              (reader.ReadToEnd().Replace(string.Format("{0}/",folder), 
              string.Empty)), Environment.NewLine);
            Console.WriteLine("Directory List Complete, status {0}", 
                              ftpWebResponse.StatusDescription);
            reader.Close();
            ftpWebResponse.Close();

            return directoryFiles;

        }

        private bool DeleteFtpFile(string fileName, string folder)
        {
            ftpWebRequest = (FtpWebRequest)WebRequest.Create(
              new Uri(string.Format("{0}/{1}/{2}", 
              ftpEntity.FtpServer, folder, fileName)));
            this.operation = OperationType.Delete;
            ChooseOperationType();
            SettingFtpManager();

            FtpWebResponse ftpWebResponse = 
                   (FtpWebResponse)ftpWebRequest.GetResponse();
            Console.WriteLine("Delete status: {0}", 
                              ftpWebResponse.StatusDescription);

            ftpWebResponse.Close();
            return true;
        }


        private void SettingFtpManager()
        {
            ftpWebRequest.Credentials = 
              new NetworkCredential(ftpEntity.Username, ftpEntity.Password);

            // By default KeepAlive is true,
            // where the control connection is not closed
            // after a command is executed.
            ftpWebRequest.KeepAlive = false;
            ftpWebRequest.UseBinary = true;
        }

        private void ChooseOperationType()
        { 
            switch(operation)
            {
                case OperationType.Upload:
                    ftpWebRequest.Method = WebRequestMethods.Ftp.UploadFile;
                    break;
                case OperationType.Delete:
                    ftpWebRequest.Method = WebRequestMethods.Ftp.DeleteFile;
                    break;
                case OperationType.List:
                    ftpWebRequest.Method = WebRequestMethods.Ftp.ListDirectory;
                    break;
            }
        }
    }
}

Here is the code for FTPEntity:

C#
using System;
using System.Collections.Generic;
using System.Text;

namespace George.WWF.Activities.FTP
{
    public class FtpEntity
    {
        string ftpServer, username, password;
        
        public string FtpServer
        {
            get { return ftpServer; }
        }

        public string Username
        {
            get { return username; }
        }

        public string Password
        {
            get { return password; }
        }


        /// <summary>
        /// Represent an FTP server
        /// </summary>
        /// <param name="ftpServer">FTP server url</param>
        /// <param name="username">username to access
        /// the server. Example : (10.50.26.123) or (www.target.com)
        /// or (ftp://www.target.com)</param>
        /// <param name="password">password to access the server</param>
        public FtpEntity(string ftpServer, string username, string password)
        {
            this.ftpServer = FormatFtpServer(ftpServer);
            this.username = username;
            this.password = password;
        }

        private string FormatFtpServer(string ftpServer)
        {
            if(!ftpServer.StartsWith("ftp://"))
                ftpServer = "ftp://" + ftpServer;
            return ftpServer;
        }
    }
}

Points of interest

The support to design-time is a feature that can make a big difference during development and add extra value to classic class libraries. Windows Workflow Foundation provides great instruments to build applications but lack in controls (most of them are not free); this article provides the first steps to build your own custom activity.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)