|
众所周知,在MOSS 2007 中,当我们为List中的某一个Item上传附件的时候,这个附件是以二进制的形式存放在数据库中的,当我们需要下载的时候,SharePoint Service再为我们还原成原来的附件。SharePoint 还为附件的大小做了限制,一般都在50M。那么如果有的用户想把一些大Size 的文件作为附件上传的时候,就会产生问题。而且大文件上传,下载均设计到数据库操作,对系统的性能要求会比较大。我们在曾经遇到过美国的同事上传附件到在中国的SharePoint server上,由于附件比较大,带宽有限,就产生过上传出错的问题。还有在MOSS2007中,附件没办法批量上传和下载到List的某个Item中,用户只要one by one的去下载附件,用户体验不够友好。
综上需求,开发了一个自定义字段:FTP上传字段。功能如下:
1.当用户在一个List下新建一个Item的时候,在用户设定的FTP server上自动创建一个文件夹。
2.文件夹地址作为自定义字段的值显示,用户可以点击这个链接地址,进行批量的附件上传下载。
下面介绍详细的开发过程:
1.首先还是创建一个自定义字段的Project
2.先添加一个FTP的操作的工具类,我们称为FTPClientUtility,完成一切在FTP server上的操作,如附件上传,创建文件夹,计算文件夹当前大小等等
FTPClientUtility的主要方法如下:
代码
public bool UploadFile(string path, string fileName, string location)
{
StreamReader sourceStream = null;
Stream requestStream = null;
FtpWebResponse response = null;
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(this.FTPUrl + "/" + location + "/" + fileName);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UseBinary = true;
request.Credentials = new NetworkCredential(this.UserName, this.Password);
sourceStream = new StreamReader(path);
byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
response = (FtpWebResponse)request.GetResponse();
// string result = response.StatusDescription;
response.Close();
return true;
}
catch (Exception ex)
{
return false;
}
finally
{
if (null != sourceStream)
{
sourceStream.Close();
}
if (null != requestStream)
{
requestStream.Close();
}
if (null != response)
{
response.Close();
}
}
}
public bool CreateFolder(string folderName)
{
FtpWebResponse response = null;
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(this.FTPUrl + "/" + folderName);
request.Method = WebRequestMethods.Ftp.MakeDirectory;
request.UseBinary = true;
request.Credentials = new NetworkCredential(this.UserName, this.Password);
response = (FtpWebResponse)request.GetResponse();
response.Close();
return true;
}
catch (Exception ex)
{
return false;
}
finally
{
if (null != response)
{
response.Close();
}
}
}
public bool IsFolderOrFileExist(string folderName, string destinationFolderLocation)
{
FtpWebResponse response = null;
StreamReader reader = null;
IList fileList = new List();
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(this.FTPUrl + destinationFolderLocation);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.UseBinary = true;
request.Credentials = new NetworkCredential(this.UserName, this.Password);
response = (FtpWebResponse)request.GetResponse();
reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string line = String.Empty;
while(!String.IsNullOrEmpty(line = reader.ReadLine()))
{
line = line.Split('_')[0];
fileList.Add(line);
}
response.Close();
reader.Close();
string folderId = folderName.Split('_')[0];
return fileList.Contains(folderId);
}
catch (Exception ex)
{
return false;
}
finally
{
if (null != response)
{
response.Close();
}
if (null != reader)
{
reader.Close();
}
}
}
public List GetListDirectoryDetails(string destinationFolderLocation)
{
StreamReader reader = null;
FtpWebResponse response = null;
List fileList = new List();
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(this.FTPUrl + destinationFolderLocation);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.UseBinary = true;
request.Credentials = new NetworkCredential(this.UserName, this.Password);
response = (FtpWebResponse)request.GetResponse();
reader = new StreamReader(response.GetResponseStream());
string line = "";
string fileName = "";
string folderName = "";
string[] info = null;
IList filesInfo = new List();
while (!String.IsNullOrEmpty(line = reader.ReadLine())) //Save the response stream in memory so the response can be closed and will not hanged in
{
filesInfo.Add(line);
}
int startIndex = 0;
System.Text.RegularExpressions.Regex rg = new System.Text.RegularExpressions.Regex(@"\d");
foreach (string fileLine in filesInfo)
{
if (fileLine.IndexOf("") == -1)
{
fileName = rg.Replace(fileLine.Substring(20), "").Trim();
fileList.Add(fileName);
}
else
{
startIndex = fileLine.IndexOf("");
folderName = fileLine.Substring(startIndex + 5, fileLine.Length - startIndex - 5).Trim();
fileList.Add(folderName);
}
}
response.Close();
return fileList;
}
catch (Exception ex)
{
return null;
}
}
public long GetFolderSize(string destinationFolderLocation)
{
long fileSize = 0;
StreamReader reader = null;
FtpWebResponse response = null;
long totalFileSize = 0;
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(this.FTPUrl + destinationFolderLocation);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.UseBinary = true;
request.Credentials = new NetworkCredential(this.UserName,this.Password);
response = (FtpWebResponse)request.GetResponse();
reader = new StreamReader(response.GetResponseStream());
string line = "";
string fileName = "";
string folderName = "";
string[] info = null;
IList filesInfo = new List();
while (!String.IsNullOrEmpty(line = reader.ReadLine())) //Save the response stream in memory so the response can be closed and will not hanged in
{
filesInfo.Add(line);
}
int startIndex = 0;
foreach (string fileLine in filesInfo)
{
if (fileLine.IndexOf("") == -1)
{
info = fileLine.Split(' ');
fileName = info[info.Length - 1];
totalFileSize += Convert.ToInt64(info[info.Length - 2]);
}
else
{
startIndex = fileLine.IndexOf("");
folderName = fileLine.Substring(startIndex + 5, fileLine.Length - startIndex - 5).Trim();
response.Close();
totalFileSize += GetFolderSize(destinationFolderLocation + "/" + folderName);
}
}
return totalFileSize;
}
catch (Exception ex)
{
return 0;
}
}
public long GetFileSize(string fileName, string destinationFolderLocation)
{
long fileSize = 0;
FtpWebResponse response = null;
try
{
FileInfo fileInf = new FileInfo(fileName);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(this.FTPUrl + destinationFolderLocation + "/" + fileInf.Name);
request.Method = WebRequestMethods.Ftp.GetFileSize;
request.UseBinary = true;
request.Credentials = new NetworkCredential(this.UserName, this.Password);
response = (FtpWebResponse)request.GetResponse();
fileSize = response.ContentLength;
response.Close();
return fileSize;
}
catch (Exception ex)
{
return 0;
}
finally
{
if (null != response)
{
response.Close();
}
}
}
3. 自定义字段的实现类,和普通的自定义字段实现类类似,没什么特别的,代码如下
代码
public class FileUploadField : SPFieldText
{
public FileUploadField(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
InitProperties();
}
public FileUploadField(SPFieldCollection fields, string typeName, string displayName)
: base(fields, typeName, displayName)
{
InitProperties();
}
public override BaseFieldControl FieldRenderingControl
{
get
{
BaseFieldControl fieldControl = new FileUploadFieldControl(this);
fieldControl.FieldName = InternalName;
return fieldControl;
}
}
}
4. 自定义字段的呈现类,当Item新建时,要完成在FTP上创建相应的文件夹的工作,当用户Edit/View时,将创建的文件夹地址作为此字段的值显示,主要代码:
代码
public class FileUploadFieldControl : BaseFieldControl
{
private FileUploadField field;
private LinkButton updateLink;
private HyperLink fileLink;
private FTPClientUtility ftpUtility;
private HtmlTable fileTable;
long folderMaxSize;
public FileUploadFieldControl(FileUploadField parentField)
{
this.field = parentField;
this.updateLink = new LinkButton();
this.fileLink = new HyperLink();
this.ftpUtility = new FTPClientUtility();
this.fileTable = new HtmlTable();
Dictionary ftpInfo = GetFtpUrl();
ftpUtility.FTPUrl = ftpInfo["Url"];
ftpUtility.UserName = ftpInfo["UserName"];
ftpUtility.Password = ftpInfo["Password"];
folderMaxSize = Convert.ToInt64(ftpInfo["FolderSize"]);
}
private Dictionary GetFtpUrl()
{
string ftpFile = Environment.CurrentDirectory + "\\FtpInfo.xml";
Dictionary ftpInfo = new Dictionary();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(ftpFile);
string ftpUrl = xmlDoc.DocumentElement.SelectSingleNode("//Url").InnerText;
ftpInfo.Add("Url", ftpUrl);
string userName = xmlDoc.DocumentElement.SelectSingleNode("//UserName").InnerText;
ftpInfo.Add("UserName", userName);
string password = xmlDoc.DocumentElement.SelectSingleNode("//Password").InnerText;
ftpInfo.Add("Password", password);
string folderSize = xmlDoc.DocumentElement.SelectSingleNode("//FolderSize").InnerText;
ftpInfo.Add("FolderSize", folderSize);
return ftpInfo;
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
}
protected override void CreateChildControls()
{
base.CreateChildControls();
try
{
if (null == this.updateLink)
{
this.updateLink = new LinkButton();
}
string backUrl = String.Empty;
string webUrl = SPContext.Current.Web.Url;
string formUrl = String.Empty;
if(this.ControlMode == SPControlMode.Edit || this.ControlMode == SPControlMode.Display)
{
string webID = SPContext.Current.Web.ID.ToString();
string webName = SPContext.Current.Web.Title;
string webFolderName = webID + "_" + webName;
string listID = SPContext.Current.ListId.ToString();
string listName = SPContext.Current.List.Title;
string listFolderName = listID + "_" + listName;
string itemID = SPContext.Current.ItemId.ToString();
//if item fold has been created, this field layouted as a html link, else this field layouted as a link button
if (ftpUtility.IsFolderOrFileExist(webFolderName, ""))
{
//list folder has been created on FTP
if (ftpUtility.IsFolderOrFileExist(listFolderName, "/" + webFolderName))
{
//item folder has been created
if (ftpUtility.IsFolderOrFileExist(itemID, "/" + webFolderName + "/" + listFolderName))
{
long folderSize = ftpUtility.GetFolderSize("/" + webFolderName + "/" + listFolderName + "/" + itemID);
string js = String.Empty;
if (folderSize > this.folderMaxSize)
{
js = "alert('This folder is full without any space, you cannot upload any file before you clean up it.');";
}
else
{
js = "window.open('" + this.ftpUtility.FTPUrl + "/" + webFolderName + "/" + listFolderName + "/" + itemID + "','','height=500,width=700,toolbar=yes,status=no');";
}
this.fileLink.Attributes.Add("onclick", js);
js = "this.style.textDecoration = 'underline'; this.style.cursor='hand';";
this.fileLink.Attributes.Add("onmouseover", js);
this.fileLink.Attributes.Add("onmouseout", "this.style.textDecoration = 'none'");
this.fileLink.Text = "Attachment";
List fileList = ftpUtility.GetListDirectoryDetails("/" + webFolderName + "/" + listFolderName + "/" + itemID);
HtmlTableRow tableRow = null;
HtmlTableCell cell = null;
foreach(string file in fileList)
{
tableRow = new HtmlTableRow();
cell = new HtmlTableCell();
cell.Attributes.Add("Class", "ms-vb");
cell.InnerHtml ="" + file + "";
tableRow.Cells.Add(cell);
this.fileTable.Rows.Add(tableRow);
}
this.Controls.Clear();
this.Controls.Add(fileLink);
this.Controls.Add(this.fileTable);
}
else
{
this.updateLink.Click += new EventHandler(updateLink_Click);
this.updateLink.Text = "Attachment";
this.Controls.Clear();
this.Controls.Add(updateLink);
}
}
else
{
this.updateLink.Click += new EventHandler(updateLink_Click);
this.updateLink.Text = "Attachment";
this.Controls.Clear();
this.Controls.Add(updateLink);
}
}
else
{
this.updateLink.Click += new EventHandler(updateLink_Click);
this.updateLink.Text = "Attachment";
this.Controls.Clear();
this.Controls.Add(updateLink);
}
}
else if (this.ControlMode == SPControlMode.New)
{
this.fileLink.Text = "Attachment(Please update and download files in edit page.)";
this.Controls.Clear();
this.Controls.Add(fileLink);
}
}
catch (Exception)
{
;
}
}
protected void updateLink_Click(object sender, EventArgs e)
{
string webID = SPContext.Current.Web.ID.ToString();
string webName = SPContext.Current.Web.Title;
string webFolderName = webID + "_" + webName;
string listID = SPContext.Current.ListId.ToString();
string listName = SPContext.Current.List.Title;
string listFolderName = listID + "_" + listName;
string itemID = SPContext.Current.ItemId.ToString();
try
{
if (ftpUtility.IsFolderOrFileExist(webFolderName, ""))
{
if (ftpUtility.IsFolderOrFileExist(listFolderName, "/" + webFolderName))
{
if (ftpUtility.IsFolderOrFileExist(itemID, "/" + webFolderName + "/" + listFolderName))
{
return;
}
else
{
this.ftpUtility.CreateFolder(webFolderName + "/" + listFolderName + "/" + itemID);
}
}
else
{
this.ftpUtility.CreateFolder(webFolderName + "/" + listFolderName);
this.ftpUtility.CreateFolder(webFolderName + "/" + listFolderName + "/" + itemID);
}
}
else
{
this.ftpUtility.CreateFolder(webFolderName);
this.ftpUtility.CreateFolder(webFolderName + "/" + listFolderName);
this.ftpUtility.CreateFolder(webFolderName + "/" + listFolderName + "/" + itemID);
}
//Context.Response.Redirect(this.ftpUtility.FTPUrl + "/" + webFolderName + "/" + listFolderName + "/" + itemID);
string js = "window.open('" + this.ftpUtility.FTPUrl + "/" + webFolderName + "/" + listFolderName + "/" + itemID + "','','height=500,width=700,toolbar=yes,status=no') ";
Context.Response.Write(js);
}
catch
{
return;
}
}
protected override void Render(HtmlTextWriter output)
{
base.Render(output);
if (this.ControlMode == SPControlMode.Display)
{
string webID = SPContext.Current.Web.ID.ToString();
string webName = SPContext.Current.Web.Title;
string webFolderName = webID + "_" + webName;
string listID = SPContext.Current.ListId.ToString();
string listName = SPContext.Current.List.Title;
string listFolderName = listID + "_" + listName;
string itemID = SPContext.Current.ItemId.ToString();
if (ftpUtility.IsFolderOrFileExist(webFolderName, ""))
{
//list folder has been created on FTP
if (ftpUtility.IsFolderOrFileExist(listFolderName, "/" + webFolderName))
{
//item folder has been created
if (ftpUtility.IsFolderOrFileExist(itemID, "/" + webFolderName + "/" + listFolderName))
{
string uploadFileHref = "Attachment";
output.Write(uploadFileHref);
}
else
{
output.Write("Please create file repository in edit page");
}
}
}
}
}
public override void UpdateFieldValueInItem()
{
this.EnsureChildControls();
try
{
this.Value = this.updateLink.Text;
this.ItemFieldValue = this.Value;
}
catch (Exception)
{
;
}
}
public override object Value
{
get
{
this.EnsureChildControls();
if (this.updateLink != null)
return "";
else
return null;
}
}
}
可以在代码中发现,在FTP上创建的文件夹按照"WebID/ListID/ItemID"的层次结构创建。避免了文件夹的重复创建以及附件的分类问题。
接下来可以创建一个.xml文件,将FTP server的地址,用户的ID和密码写入,当这些基础信息发生改变时,只要配置这个Xml文件即可而不需要修改代码。部署时将此XML文件放入 "系统目录\Windows\system32\inetsrv,以确保能够被我们的自定义字段程序访问。
部署完此字段,为任何一个List添加自定义字段,下面是效果图:
新建Item:
编辑Item:
点击Attachment链接,打开ftp目录,就可以上传下载属于此Item的附件了:
安装文件可以在此下载:/Files/tonnie/AECSharePoint.Field.FileTransfer.rar
欢迎指正!谢谢!
|
|