youngfan007 发表于 2015-5-26 09:46:15

[SharePoint 开发详解] 自定义字段开发 II: FTP上传字段

  众所周知,在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('_');
                  fileList.Add(line);
                }
                response.Close();
                reader.Close();
                string folderId = folderName.Split('_');
                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;
                        totalFileSize += Convert.ToInt64(info);
                  }
                  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
  欢迎指正!谢谢!
  
页: [1]
查看完整版本: [SharePoint 开发详解] 自定义字段开发 II: FTP上传字段