写在前面
刚入职一家新公司,在对接app的时候需要获取到某公司的sharepoint上面的文档库,获取文档库列表,团队文档库中的文件和文件夹列表,个人文档库中的文件文件夹列表,及在app端进入文件夹的时候需要获取该文件夹下的文件及文件夹列表,对文件的上传下载等操作。
对rest api的使用,完全是小白,具体也不知道怎么实现,在编写过程中查找了很多资料,发现这方面的资料极其少,也有可能是对自己对这个技术完全的不了解,所以在查找方向上面有问题。最后算是实现了上面的功能,这里做一下记录,以及提供一些参考资料。
实现过程
在如果注册app以及注册发布者的操作步骤,可以参考我之前的一篇文章:Rest API的简单应用,这里介绍了如何注册app和发布者的操作步骤,也包括了如何使用高安全的访问方式。希望对你有所帮助。项目的简单描述,本项目实现方式是一个server to server的方式,在app请求iis上面部署的接口,然后该iis服务器再去请求sharepoint服务器的api,获取文档库的相关信息。流程是大概这样的一个流程。
注册的发布者:所有的操作可以使用同一个发布者。
团队文档库:可以使用同一个ClientID
个人文档库:每一个人对应一个ClientID。
查询方式使用了OData的方式,关于OData的查询方式,可以参考这篇文章
https://msdn.microsoft.com/zh-SG/library/fp142385
查询
查询单个文件的信息
1 /// <summary>
2 /// 根据文件在服务端的相对url获取文件信息
3 /// </summary>
4 /// <param name="serverRelativeUrl">文件在服务端的相对url</param>
5 /// <returns>文件信息的json</returns>
6 public string GetFileInfoByRelativeUrl(string serverRelativeUrl)
7 {
8 ///Personal/chenwd/Documents/Shared with Everyone
9 string queryFileApi = "GetFileByServerRelativeUrl('" + serverRelativeUrl + "')";
10 string filter = "?$select=" + new Document.Core.Model.Document().ToString();
11 if (_documentType == Model.DocumentType.Personal)
12 {
13 RequestHelper.ClientID = _dicMapping[_userName];
14 }
15 string strFileJson = RequestHelper.RequestGet(_userName, _appUrl, queryFileApi + filter, _documentType);
16 return strFileJson.ToJson("200");
17 }
这里将文件信息封装成为一个类,并重写了tostring方法,方便操作。

1 /// <summary>
2 /// 文档信息实体类
3 /// </summary>
4 public class Document
5 {
6 /// <summary>
7 /// 签入描述
8 /// </summary>
9 public string CheckInComment { get; set; }
10 /// <summary>
11 /// 签出类型
12 /// </summary>
13 public string CheckOutType { get; set; }
14 /// <summary>
15 /// 内容Tag
16 /// </summary>
17 public string ContentTag { get; set; }
18 /// <summary>
19 /// CustomizedPageStatus
20 /// </summary>
21 public string CustomizedPageStatus { get; set; }
22 /// <summary>
23 /// 独占签出标识
24 /// </summary>
25 public string ETag { get; set; }
26 /// <summary>
27 /// 是否存在
28 /// </summary>
29 public string Exists { get; set; }
30 /// <summary>
31 /// 大小
32 /// </summary>
33 public string Length { get; set; }
34 /// <summary>
35 /// 等级
36 /// </summary>
37 public string Level { get; set; }
38 /// <summary>
39 /// 主要版本
40 /// </summary>
41 public string MajorVersion { get; set; }
42 /// <summary>
43 /// 次版本
44 /// </summary>
45 public string MinorVersion { get; set; }
46 /// <summary>
47 /// 文档名称
48 /// </summary>
49 public string Name { get; set; }
50 /// <summary>
51 /// 文档服务端相对地址
52 /// </summary>
53 public string ServerRelativeUrl { get; set; }
54 /// <summary>
55 /// 创建时间
56 /// </summary>
57 public string TimeCreated { get; set; }
58 /// <summary>
59 /// 最后一次修改时间
60 /// </summary>
61 public string TimeLastModified { get; set; }
62 /// <summary>
63 /// 描述
64 /// </summary>
65 public string Title { get; set; }
66 /// <summary>
67 /// 版本
68 /// </summary>
69 public string UIVersion { get; set; }
70 /// <summary>
71 /// 版本标识
72 /// </summary>
73 public string UIVersionLabel { get; set; }
74 public override string ToString()
75 {
76 Type type = this.GetType();
77 PropertyInfo[] pros = type.GetProperties();
78 string str = string.Empty;
79 foreach (var item in pros)
80 {
81 str += item.Name + ",";
82 }
83 return str.TrimEnd(',');
84 }
85 }

然后使用Odata查询,获取需要的字段的值。
请求辅助类
RequestHelper
为string做扩展方法,将结果使用自定义的格式包裹成json格式。
StringExtention
查询某个相对服务端的Url下的所有文件及文件夹
1 /// <summary>
2 /// 根据文档在服务端的相对Url获取文档信息
3 /// </summary>
4 /// <param name="serverRelativeUrl"></param>
5 /// <returns></returns>
6 public string GetDocmumentsByRelativeUrl(string serverRelativeUrl)
7 {
8 ///Personal/chenwd/Documents/Shared with Everyone
9 string queryFileApi = "GetFolderByServerRelativeUrl('" + serverRelativeUrl + "')/Files";
10 string queryFolderApi = "GetFolderByServerRelativeUrl('" + serverRelativeUrl + "')/Folders";
11
12 string filter = "?$select=" + new Document.Core.Model.Document().ToString();
13 if (_documentType == Model.DocumentType.Personal)
14 {
15 RequestHelper.ClientID = _dicMapping[_userName];
16 }
17 string strFileJson = RequestHelper.RequestGet(_userName, _appUrl, queryFileApi + filter, _documentType);
18 string strFolderJson = RequestHelper.RequestGet(_userName, _appUrl, queryFolderApi + filter, _documentType);
19 return strFolderJson.ToMergeJson("200", strFileJson);
20 }
根据文档库的URL查询所有的文件及文件夹

1 /// <summary>
2 /// 根据url获取该url下的所有的文档信息
3 /// </summary>
4 /// <param name="docSiteUrl"></param>
5 /// <returns></returns>
6 public string GetDocumentsByUrl(string docSiteUrl)
7 {
8 //docsiteUrl格式:http://my.xxx.com/Personal/cxxx/Documents/Forms/All.aspx
9 //解析出文档库服务端的相对路径
10 int startIndex = docSiteUrl.IndexOf("//") + 2;
11 string strRelativeUrl = docSiteUrl.Substring(startIndex);
12 string[] strUrls = strRelativeUrl.Split(new char[] { '/' });
13 strRelativeUrl = "/" + strUrls[1] + "/" + strUrls[2] + "/" + strUrls[3] + "/";
14 string queryFileApi = "GetFolderByServerRelativeUrl('" + strRelativeUrl + "')/Files";
15 string queryFolderApi = "GetFolderByServerRelativeUrl('" + strRelativeUrl + "')/Folders";
16 string filter = "?$select=" + new Document.Core.Model.Document().ToString();
17 if (_documentType == Model.DocumentType.Personal)
18 {
19 RequestHelper.ClientID = _dicMapping[_userName];
20 }
21 string strFileJson = RequestHelper.RequestGet(_userName, _appUrl, queryFileApi + filter, _documentType);
22 string strFolderJson = RequestHelper.RequestGet(_userName, _appUrl, queryFolderApi + filter, _documentType);
23 return strFolderJson.ToMergeJson("200", strFileJson);
24 }

移动文件
1 /// <summary>
2 /// 移动
3 /// </summary>
4 /// <param name="serverFileUrl"></param>
5 /// <param name="newFileUrl"></param>
6 /// <returns></returns>
7 public string MoveTo(string serverFileUrl, string newFileUrl)
8 {
9 string strMoveToApi = "GetFileByServerRelativeUrl('" + serverFileUrl + "')/moveto(newurl='" + newFileUrl + "',flags=1)";
10
11 if (_documentType == Model.DocumentType.Personal)
12 {
13 RequestHelper.ClientID = _dicMapping[_userName];
14 }
15 return RequestHelper.RequestPost(_userName, _appUrl, strMoveToApi, _documentType);
16 }
1 /// <summary>
2 /// 创建文件夹
3 /// </summary>
4 /// <param name="serverRelativeUrl"></param>
5 /// <param name="folderName"></param>
6 /// <returns></returns>
7 public string CreateFolder(string serverRelativeUrl, string folderName)
8 {
9 serverRelativeUrl = serverRelativeUrl.StartsWith("/", StringComparison.CurrentCulture) ? serverRelativeUrl : "/" + serverRelativeUrl;
10 string createFolderApi = "folders/add('" + serverRelativeUrl + "/" + folderName + "')";
11
12 if (_documentType == Model.DocumentType.Personal)
13 {
14 RequestHelper.ClientID = _dicMapping[_userName];
15 }
16 return RequestHelper.RequestPost(_userName, _appUrl, createFolderApi, _documentType);
17 }
将所需的字段封装为文档库实体,方便以后的操作
DocumentSite
根据文档库的模板获取所有的文档库列表json
1 /// <summary>
2 /// 获得所有的文档库列表
3 /// </summary>
4 /// <returns></returns>
5 public string GetCoworkDocumentSiteList()
6 {
7 string queryApi = "lists?$filter=BaseTemplate eq 101&$select=" + new Document.Core.Model.DocumentSite().ToString();
8 return RequestHelper.RequestGet(_userName, _appUrl, queryApi, _documentType);
9 }
下载:通过api从sharepoint服务器下载文件到iis服务器,然后返回该文件的在iis服务器的相对路径。当然可以直接返回byte[],这里不知道为什么要有该操作也是比较迷惑的地方,api提供的方式完全可以返回byte[]

1 /// <summary>
2 /// 下载文件
3 /// </summary>
4 /// <param name="serverRelativeUrl">文件在服务端的相对路径</param>
5 /// <param name="fileLength"></param>
6 /// <returns></returns>
7 public string DownLoadFile(string serverRelativeUrl, int fileLength)
8 {
9 string loadApi = "GetFileByServerRelativeUrl('" + serverRelativeUrl + "')/openbinarystream";
10 string strJson = string.Empty;
11 try
12 {
13 string saveServerRelativeUrl = "DownLoad\\" + _userName + "\\";
14 string filePath = AppDomain.CurrentDomain.BaseDirectory + saveServerRelativeUrl;
15 string fileName = serverRelativeUrl.Substring(serverRelativeUrl.LastIndexOf('/') + 1);
16 //"Personal\\chenwd\\Documents\\Shared with Everyone\\SharePoint"
17 string relativeDir = serverRelativeUrl.Substring(0,
18 serverRelativeUrl
19 .LastIndexOf('/'))
20 .Replace('/', '\\')
21 .TrimStart("\\".ToCharArray());
22 filePath = filePath + relativeDir;
23 if (!Directory.Exists(filePath))
24 {
25 Directory.CreateDirectory(filePath);
26 }
27 filePath = filePath + "\\" + fileName;
28 if (_documentType == Model.DocumentType.Personal)
29 {
30 RequestHelper.ClientID = _dicMapping[_userName];
31 }
32 RequestHelper.RequestGet(_appUrl, loadApi, filePath, fileLength, _documentType);
33 saveServerRelativeUrl = "\\" + saveServerRelativeUrl + relativeDir + "\\" + fileName;
34 saveServerRelativeUrl = saveServerRelativeUrl.Replace('\\', '/');
35 string strFolderJson = string.Empty;
36 strJson = strFolderJson.ToDownLoadJson("200", saveServerRelativeUrl);
37 }
38 catch (WebException ex)
39 {
40 strJson = string.Empty.ToErrorJson("500", ex.Message);
41 }
42 return strJson;
43 }

上传文件是最头疼的地方,在网上查找了很多方法,最后是以下面的方式操作的。
1 /// <summary>
2 /// 上传文件
3 /// </summary>
4 /// <param name="serverReleativeUrl">文件夹的相对路径</param>
5 /// <param name="fileName"></param>
6 /// <returns>返回下载地址</returns>
7 public string UploadFile(string serverReleativeUrl, string fileName, byte[] data, bool bOverWrite)
8 {
9 ClientContext spContext = new ClientContext(_appUrl);
10 //认证方式
11 spContext.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication;
12 Web website = spContext.Web;
13 Folder folder = website.GetFolderByServerRelativeUrl(serverReleativeUrl);
14 try
15 {
16 FileCreationInformation file = new FileCreationInformation();
17 file.Content = data;
18 file.Url = fileName;
19 file.Overwrite = bOverWrite;
20 folder.Files.Add(file);
21 spContext.ExecuteQuery();
22 }
23 catch (Exception ex)
24 {
25 return string.Empty.ToErrorJson("500", ex.Message);
26 }
27 return string.Empty.ToSuccessJson("200", "上传成功");
28 }
拷贝
1 public string CopyTo(string soureRelativeUrl, string desRelativeUrl)
2 {
3 string strCopyApi = "GetFileByServerRelativeUrl('" + soureRelativeUrl + "')/copyto(strnewurl='" + desRelativeUrl + "',boverwrite=false)";
4 if (_documentType == Model.DocumentType.Personal)
5 {
6 RequestHelper.ClientID = _dicMapping[_userName];
7 }
8 return RequestHelper.RequestPost(_userName, _appUrl, strCopyApi, _documentType);
9 }
总结
在写接口的时候,在文件上传的地方,卡了一天的时间,也就是昨天的时候,突然查询了Miscrosoft.SharePoint.Client下的File类,才在网上看到那种实现方式,在群里也问了一些搞sharepoint的朋友,说那种方式操作起来更简单一些,如果用Msdn中提到的那种方式使用Post提交数据,需要在请求头中加一些参数。试了很多次无果,不得不放弃了。
下面是一些参考文章,希望对你有所帮助
https://msdn.microsoft.com/zh-SG/library/fp142385 OData相关
https://msdn.microsoft.com/zh-cn/library/jj164022.aspx
使用ClientObjectModel访问SharePoint数据
http://blogs.msdn.com/b/uksharepoint/archive/2013/04/20/uploading-files-using-the-rest-api-and-client-side-techniques.aspx
http://my.oschina.net/edens/blog/115601