Skip to content

Instantly share code, notes, and snippets.

@zhenyanghua
Last active January 22, 2018 14:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zhenyanghua/c4356a8a0e239efda8e7431dfbd664da to your computer and use it in GitHub Desktop.
Save zhenyanghua/c4356a8a0e239efda8e7431dfbd664da to your computer and use it in GitHub Desktop.
Facade Pattern Example
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using NLog;
using WebGrease.Css.Ast.Selectors;
namespace Utilities
{
/// <summary>
/// This is a facade pattern example of simplify the .Net Ftp class API.
/// It provides a easy to use interface for the client to do basic FTP operations.
/// </summary>
/// <author>
/// Zhenyang Hua
/// </author>
class FtpUtility
{
/// <summary>
/// This is a configuration struct for instantiate a FtpUtility Class
/// </summary>
public struct FtpConfig
{
public string RemoteHost;
public string RemoteUser;
public string RemotePassword;
public bool IsPasv;
}
private static Logger logger = LogManager.GetCurrentClassLogger();
private readonly NetworkCredential _networkCredential;
private readonly bool _hasCredentials;
/// <summary>
/// This is the FTP configuration object instance.
/// It exposes the current configuration FtpConfig instance
/// as a property from an FtpUtility instance.
/// </summary>
public readonly FtpConfig Config;
public List<string> DownloadedFiles = new List<string>();
/// <summary>
/// This is the FtpUtility class.
/// Assign an FtpConfig object to this class to intantiate it.
/// From an instance of this classs, all methods are exposed.
/// </summary>
/// <param name="config"></param>
public FtpUtility(FtpConfig config)
{
if (!string.IsNullOrEmpty(config.RemoteUser) && !string.IsNullOrEmpty(config.RemotePassword))
{
_networkCredential = new NetworkCredential(config.RemoteUser, config.RemotePassword);
_hasCredentials = true;
}
Config = config;
}
/// <summary>
/// This provides the directory listing for the current
/// remote user's default ftp login root folder.
/// </summary>
/// <returns>A list of file and sub-directory name, or empty list</returns>
public List<string> DirectoryListing()
{
return DirectoryListing(string.Empty);
}
/// <summary>
/// This provides the directory listing for this folder
/// </summary>
/// <param name="folder">the name of the folder</param>
/// <returns>A list of file and sub-directory name, or empty list</returns>
public List<string> DirectoryListing(string folder)
{
FtpWebResponse response = GetFtpWebResponse(folder, WebRequestMethods.Ftp.ListDirectory);
Stream responseStream = response.GetResponseStream();
List<string> result = new List<string>();
if (responseStream != null)
{
StreamReader reader = new StreamReader(responseStream);
while(!reader.EndOfStream)
{
result.Add(reader.ReadLine());
}
reader.Close();
response.Close();
}
return result;
}
private FtpWebResponse GetFtpWebResponse(string folder, string method)
{
FtpWebRequest request = (FtpWebRequest) WebRequest.Create(Config.RemoteHost + folder);
if (_hasCredentials) request.Credentials = _networkCredential;
request.UsePassive = Config.IsPasv;
request.Method = method;
return (FtpWebResponse) request.GetResponse();
}
/// <summary>
/// This downloads a single file from the destination directory
/// in the FTP server
/// </summary>
/// <param name="file"></param>
/// <param name="destination"></param>
public void Download(string file, string destination)
{
FtpWebResponse response = GetFtpWebResponse(file, WebRequestMethods.Ftp.DownloadFile);
Stream responseStream = response.GetResponseStream();
if (responseStream != null)
{
StreamReader reader = new StreamReader(responseStream);
StreamWriter writer = new StreamWriter(destination);
writer.Write(reader.ReadToEnd());
logger.Debug("Retrieving \"{0}\"", file);
DownloadedFiles.Add(file);
writer.Close();
reader.Close();
}
response.Close();
}
private void DownloadAll(string parentDir, List<string> files, string destination)
{
string parentPath = parentDir == string.Empty ? "" : parentDir + "/";
foreach (string file in files)
{
try
{
Download(parentPath + file, destination + @"\" + file);
}
catch (WebException)
{
string subFolder = file;
string subFolderPath = destination + "/" + subFolder;
Directory.CreateDirectory(subFolderPath);
Regex rx = new Regex(@"(.+\/)(.+)");
parentDir = parentPath + subFolder;
List<string> subFolderList = DirectoryListing(parentDir)
.Select(x => rx.Replace(x, "$2")).ToList();
DownloadAll(parentDir, subFolderList, subFolderPath);
}
}
}
/// <summary>
/// This downloads a list of files from the destination directory
/// in the FTP server.
/// </summary>
/// <param name="files"></param>
/// <param name="destination"></param>
public int DownloadBatch (List<string> files, string destination)
{
string parentPath = string.Empty;
DownloadAll(parentPath, files, destination);
return DownloadedFiles.Count;
}
/// <summary>
/// This delete a single file from the ftp server.
/// </summary>
/// <param name="file">
/// File should include the relative path to the host name.
/// Use forward slash to represent one level of directory.
/// </param>
/// <example>"foo.txt"</example>
/// <example>"myfolder/foo.txt"</example>
/// <example>"myfolder/bar/foo.txt"</example>
public void DeleteFile(string file)
{
FtpWebResponse response = GetFtpWebResponse(file, WebRequestMethods.Ftp.DeleteFile);
logger.Debug("Deleting \"{0}\"", file);
logger.Debug("Delete status: {0}", response.StatusDescription);
response.Close();
}
/// <summary>
/// This delete an empty directory from the ftp server.
/// </summary>
/// <param name="directory">
/// Directory should include the relative path to the host name.
/// Use forward slash to represent one level of directory.
/// </param>
/// <example>"myDirectory"</example>
/// <example>"foo/bar"</example>
/// <remarks></remarks>
public void DeleteDirectory(string directory)
{
FtpWebResponse response = GetFtpWebResponse(directory, WebRequestMethods.Ftp.RemoveDirectory);
logger.Debug("Deleting \"{0}\"", directory);
logger.Debug("Delete status: {0}", response.StatusDescription);
response.Close();
}
/// <summary>
/// This delete a list of files and directories from the current
/// FTP remote user's default login root folder.
/// </summary>
/// <param name="files">A list of files and sub-directories</param>
public void DeleteBatch(List<string> files)
{
string parentDir = string.Empty;
DeleteAll(parentDir, files, files);
}
private void DeleteAll(string parentDir, List<string> files, List<string> exclusions)
{
string parentPath = parentDir == string.Empty ? "" : parentDir + "/";
foreach (var file in files.Select((value,index) => new {index, value}))
{
try
{
DeleteFile(parentPath + file.value);
if (file.index == files.Count - 1 && parentPath != string.Empty)
{
if (!parentPath.StartsWith(parentDir))
DeleteDirectory(parentPath);
}
}
catch (WebException)
{
string subFolder = file.value;
Regex rx = new Regex(@"(.+\/)(.+)");
parentDir = parentPath + subFolder;
List<string> subFolderList = DirectoryListing(parentDir)
.Select(x => rx.Replace(x, "$2")).ToList();
if (subFolderList.Count == 0)
{
if (!exclusions.Contains(parentDir))
DeleteDirectory(parentDir);
} else
{
DeleteAll(parentDir, subFolderList, new List<string>());
if (file.index == files.Count - 1 && parentPath != string.Empty)
{
DeleteDirectory(parentPath);
}
}
}
}
}
public void RemoveDownloadedFiles()
{
foreach (string file in DownloadedFiles)
{
try
{
DeleteFile(file);
}
catch (WebException ex)
{
logger.Warn(ex.Message);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment