我有一个使用ftp和sftp调用的项目(使用System.Net.FtpClient和Renci.SshNet)。我想在两种情况下都有标准调用,即使用相同的参数调用Connect函数和Upload函数。我觉得我必须使用一个界面,但我是绿色的接口,我卡住了。我在这里需要一些指示。到目前为止我实现了2个功能进行测试,但它不优雅,必须有其他方法。例如,我将一个对象作为GetWorkingDirectory中的参数传递,但这感觉不对,我无法正确看到如何做到这一点。
这是我的界面:
interface IRemoteCopy
{
object Connect(string Host, int Port, string Username, string Password, string Fingerprint);
string GetWorkingDirectory(object objRemote, string Directory);
}
以下是我的课程:
public class FTPCopy : IRemoteCopy
{
public object Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
int ftpPort = 21; // default ftp port
if (Port == 0)
ftpPort = Port;
FtpClient ftp = new FtpClient();
ftp.Host = Host;
ftp.Port = ftpPort;
ftp.Credentials = new NetworkCredential(Username, Password);
return ftp;
}
public string GetWorkingDirectory(object objftp, string Directory)
{
FtpClient ftp = (FtpClient)objftp;
ftp.SetWorkingDirectory(Directory);
return ftp.GetWorkingDirectory();
}
}
public class SFTPCopy : IRemoteCopy
{
public object Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
int sftpPort = 22; // default sftp port
if (Port == 0)
sftpPort = Port;
ConnectionInfo connInfo = new ConnectionInfo(Host, sftpPort, Username, new AuthenticationMethod[]{
new PasswordAuthenticationMethod(Username, Password)
});
SftpClient sftp = new SftpClient(connInfo);
sftp.HostKeyReceived += delegate(object sender, HostKeyEventArgs e)
{
if (Fingerprint.ToLower() == (e.HostKeyName + " " + e.KeyLength + " " + BitConverter.ToString(e.FingerPrint).Replace("-", ":")).ToLower())
e.CanTrust = true;
else
e.CanTrust = false;
};
sftp.Connect();
return sftp;
}
public string GetWorkingDirectory(object objftp, string Directory)
{
return Directory;
}
}
任何人都可以在这里指导我吗?
答案 0 :(得分:1)
有几种方法可以解决这个问题。我建议你写一个ftp客户端实现的接口IWorkingDirectory,它有一个方法
GetWorkingDirectory(string dir).
IRemoteCopy的Connect方法的界面将成为:
IWorkingDirectory Connect(string Host, int Port, string Username, string Password, string Fingerprint);
然后你可以简化对
的调用public string GetWorkingDirectory(IWorkingDirectory client, string dir)
{
return client.GetWorkingDirectory(dir);
}
根据调用方法的不同,您甚至可以考虑不在IRemoteCopy中实现此方法,因为在此之前您很可能会调用Connect,因此您可以调用简单的
var client = remoteCopy.Connect(...);
client.GetWorkingDirectory(dir);
然后,您可以有效地使IRemoteCopy成为IFtpClient的抽象工厂(因为两个客户端类可能比GetWorkingDirectory方法共享更多,我建议创建一个提供所有共享功能的接口)。
我建议您查看本网站有关开放/封闭原则的信息: http://joelabrahamsson.com/a-simple-example-of-the-openclosed-principle/
编辑: 我刚刚意识到,客户端类在不同的程序集中,因此不在您的代码中。在这种情况下,最好将IRemoteCopy方法签名更改为不接收客户端作为参数。您可以在具有相应客户端的具体类中拥有一个私有字段,因为显然它们每个类总是相同的。 然后,您可以在Connect调用上设置这些字段,或直接在类实例化中设置这些字段。我更喜欢后者,因为对于IRemoteCopy的用户来说它似乎不太容易出错。
另一种可能性是将这些客户端打包成您自己的包装器(通过构建适配器 - https://en.wikipedia.org/wiki/Adapter_pattern - 或者如果基本客户端没有通过从它们继承来密封),那么您可以使用接口库我之前提出的方法。
答案 1 :(得分:0)
在探索泛型,重载方法和接口之后,我想出了这个解决方案。如果您认为有更好的事情,请告诉我们:
IDirectory.cs:
using System;
using System.Text;
namespace ReleaseManager.Interfaces
{
interface IDirectory
{
void Connect(string Host, int Port, string Username, string Password, string Fingerprint);
string GetWorkingDirectory(string Directory);
void ListDirectory(string Directory);
void CreateDirectory(string Directory);
void DeleteDirectory(string Directory);
Boolean DirectoryExists(string Directory);
void WriteAllText(string FileName, string Content, Encoding enc);
void CopyFile(string srcFile, string dstFile);
void Disconnect();
}
}
Directory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ReleaseManager.BusinessObjects
{
public class RemoteDirInfo
{
public string Name { get; set; }
public string ModifiedDate { get; set; }
}
public class RemoteFileInfo
{
public string Name { get; set; }
public string ModifiedDate { get; set; }
public long Size { get; set; }
}
public class RemoteInfo
{
public string Error { get; set; }
public string CurrentDirectory { get; set; }
public List<RemoteDirInfo> DirInfo { get; set; }
public List<RemoteFileInfo> FileInfo { get; set; }
}
}
FTPDirectory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ReleaseManager.Interfaces;
using System.Net.FtpClient;
using System.Net;
using System.Text;
using System.IO;
namespace ReleaseManager.BusinessObjects
{
public class FTPDirectory : IDirectory
{
private FtpClient client;
public RemoteInfo Info;
public FTPDirectory()
{
this.client = new FtpClient();
this.Info = new RemoteInfo();
this.Info.DirInfo = new List<RemoteDirInfo>();
this.Info.FileInfo = new List<RemoteFileInfo>();
this.Info.Error = "";
}
public void Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
int ftpPort = 21; // default ftp port
if (Port != 0)
ftpPort = Port;
this.client.Host = Host;
this.client.Port = ftpPort;
this.client.Credentials = new NetworkCredential(Username, Password);
}
public string GetWorkingDirectory(string Directory)
{
this.client.SetWorkingDirectory(Directory);
return this.client.GetWorkingDirectory();
}
public void ListDirectory(string Directory)
{
this.client.SetWorkingDirectory(Directory);
foreach (var item in this.client.GetListing(this.client.GetWorkingDirectory()))
{
switch (item.Type)
{
case FtpFileSystemObjectType.Directory:
if (item.Name != "." && item.Name != "..")
this.Info.DirInfo.Add(new RemoteDirInfo
{
Name = item.Name,
ModifiedDate = item.Modified.ToString("yyyy/MM/dd HH:mm:ss")
});
break;
case FtpFileSystemObjectType.File:
this.Info.FileInfo.Add(new RemoteFileInfo
{
Name = item.Name,
ModifiedDate = item.Modified.ToString("yyyy/MM/dd HH:mm:ss"),
Size = item.Size
});
break;
}
}
}
public void CreateDirectory(string Directory)
{
this.client.CreateDirectory(Directory);
}
public void DeleteDirectory(string Directory)
{
this.client.DeleteDirectory(Directory, true, FtpListOption.Recursive);
}
public void CopyFile(string srcFile, string dstFile)
{
using (var fileStream = System.IO.File.OpenRead(srcFile))
using (var ftpStream = this.client.OpenWrite(dstFile.Replace("\\", "/")))
{
var buffer = new byte[8 * 1024];
int count;
while ((count = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
ftpStream.Write(buffer, 0, count);
}
}
}
public void WriteAllText(string Filename, string Content, Encoding enc = null)
{
byte[] byteArray;
if (enc == null)
byteArray = Encoding.ASCII.GetBytes(Content);
else
byteArray = enc.GetBytes(Content);
using (MemoryStream stream = new MemoryStream(byteArray))
using (var ftpStream = this.client.OpenWrite(Filename.Replace("\\", "/")))
{
var buffer = new byte[8 * 1024];
int count;
while ((count = stream.Read(buffer, 0, buffer.Length)) > 0)
{
ftpStream.Write(buffer, 0, count);
}
}
}
public Boolean DirectoryExists(string Directory)
{
return this.client.DirectoryExists(Directory);
}
public void Disconnect()
{
this.client.Disconnect();
}
}
}
SFTPDirectory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ReleaseManager.Interfaces;
using Renci.SshNet;
using Renci.SshNet.Common;
using Renci.SshNet.Sftp;
using System.Text;
using System.IO;
namespace ReleaseManager.BusinessObjects
{
public class SFTPDirectory : IDirectory
{
public SftpClient client;
public RemoteInfo Info;
public SFTPDirectory()
{
this.Info = new RemoteInfo();
this.Info.DirInfo = new List<RemoteDirInfo>();
this.Info.FileInfo = new List<RemoteFileInfo>();
this.Info.Error = "";
}
public void Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
int sftpPort = 22; // default sftp port
if (Port != 0)
sftpPort = Port;
ConnectionInfo connInfo = new ConnectionInfo(Host, sftpPort, Username, new AuthenticationMethod[]{
new PasswordAuthenticationMethod(Username, Password)
});
this.client = new SftpClient(connInfo);
this.client.HostKeyReceived += delegate(object sender, HostKeyEventArgs e)
{
if (Fingerprint.ToLower() == (e.HostKeyName + " " + e.KeyLength + " " + BitConverter.ToString(e.FingerPrint).Replace("-", ":")).ToLower())
e.CanTrust = true;
else
e.CanTrust = false;
};
this.client.Connect();
}
public string GetWorkingDirectory(string Directory)
{
return Directory;
}
public void ListDirectory(string Directory)
{
List<SftpFile> files = this.client.ListDirectory(Directory).ToList();
foreach (var file in files)
{
if (file.IsDirectory)
{
if (file.Name != "." && file.Name != "..")
this.Info.DirInfo.Add(new RemoteDirInfo
{
Name = file.Name,
ModifiedDate = file.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss")
});
}
else
{
this.Info.FileInfo.Add(new RemoteFileInfo
{
Name = file.Name,
ModifiedDate = file.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss"),
Size = file.Length
});
}
}
}
public void CreateDirectory(string Directory)
{
this.client.CreateDirectory(Directory);
}
public void DeleteDirectory(string Directory)
{
this.client.DeleteDirectory(Directory);
}
public void CopyFile(string srcFile, string dstFile)
{
using (var uplfileStream = System.IO.File.OpenRead(srcFile))
{
this.client.UploadFile(uplfileStream, dstFile.Replace("\\", "/"), true);
}
}
public void WriteAllText(string Filename, string Content, Encoding enc = null)
{
byte[] byteArray;
if (enc == null)
byteArray = Encoding.ASCII.GetBytes(Content);
else
byteArray = enc.GetBytes(Content);
using (MemoryStream stream = new MemoryStream(byteArray))
{
this.client.UploadFile(stream, Filename.Replace("\\", "/"), true);
}
}
public Boolean DirectoryExists(string Directory)
{
return this.client.Exists(Directory);
}
public void Disconnect()
{
this.client.Disconnect();
}
}
}
LocalDirectory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ReleaseManager.Interfaces;
using System.Net;
using System.Text;
using System.IO;
namespace ReleaseManager.BusinessObjects
{
public class LocalDirectory : IDirectory
{
public RemoteInfo Info;
public LocalDirectory()
{
this.Info = new RemoteInfo();
this.Info.DirInfo = new List<RemoteDirInfo>();
this.Info.FileInfo = new List<RemoteFileInfo>();
this.Info.Error = "";
}
public void Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
}
public string GetWorkingDirectory(string Directory)
{
return Directory;
}
public void ListDirectory(string Directory)
{
DirectoryInfo di = new DirectoryInfo(Directory);
foreach (var item in di.EnumerateDirectories("*"))
{
if (item.Name != "." && item.Name != "..")
this.Info.DirInfo.Add(new RemoteDirInfo
{
Name = item.Name,
ModifiedDate = item.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss")
});
}
foreach (var item in di.EnumerateFiles("*"))
{
this.Info.FileInfo.Add(new RemoteFileInfo
{
Name = item.Name,
ModifiedDate = item.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss"),
Size = item.Length
});
}
}
public void CreateDirectory(string Directory)
{
System.IO.Directory.CreateDirectory(Directory);
}
public void DeleteDirectory(string Directory)
{
System.IO.Directory.Delete(Directory, true);
}
public void CopyFile(string srcFile, string dstFile)
{
System.IO.File.Copy(srcFile, dstFile);
}
public void WriteAllText(string Filename, string Content, Encoding enc = null)
{
if (enc == null)
System.IO.File.WriteAllText(Filename, Content);
else
System.IO.File.WriteAllText(Filename, Content, enc);
}
public Boolean DirectoryExists(string Directory)
{
return System.IO.Directory.Exists(Directory);
}
public void Disconnect()
{
}
}
}
RemoteBrowse方法的实现:
public JsonResult RemoteBrowse(string Protocol, string Host, int Port, string Username, string Password, string Directory, string Fingerprint = "")
{
dynamic Connector = null;
MyMember.Init(User.Identity.Name);
if (MyMember.ID_Member > 0)
{
if (Protocol == "ftp")
Connector = new FTPDirectory();
else if (Protocol == "sftp")
Connector = new SFTPDirectory();
else if (Protocol == "local")
Connector = new LocalDirectory();
if (Connector != null)
{
try
{
Connector.Connect(Host, Port, Username, Password, Fingerprint);
while (true)
{
Boolean Mod = false;
if (Directory.Length >= 2)
{
if (Directory.Substring(0, 2) == "//")
{
Directory = Directory.Substring(1);
Mod = true;
}
else if (Directory.Substring(0, 2) == "..")
{
Directory = Directory.Substring(2);
Mod = true;
}
}
else if (Directory.Length >= 3)
{
if (Directory.Substring(0, 3) == "/..")
{
Directory = Directory.Substring(3);
Mod = true;
}
}
if (!Mod)
break;
}
if (Directory.Length > 1 && Directory != "/")
{
if (Directory.Substring(0, 1) != "/")
Directory = "/" + Directory;
if (Directory.Substring(Directory.Length - 1) == "/")
Directory = Directory.Substring(0, Directory.Length - 1);
if (Directory.Substring(Directory.Length - 3) == "/..") // go one directory up
{
Directory = Directory.Substring(0, Directory.Length - 3);
Directory = Directory.Substring(0, Directory.LastIndexOf('/'));
}
}
if (Directory == "")
Directory = "/";
Connector.Info.CurrentDirectory = Connector.GetWorkingDirectory(Directory);
Connector.ListDirectory(Directory);
Connector.Disconnect();
}
catch (Exception ex)
{
Connector.Info.Error = ex.Message;
if (ex.InnerException != null)
Connector.Info.Error += '\n' + ex.InnerException.Message;
}
}
}
return Json((Connector != null) ? Connector.Info : null, JsonRequestBehavior.AllowGet);
}