作为一个应用原型系统,SharePoint提供了很多强大的应用及管理功能,但是,在实际的应用中,这些原有的功能很难满足用户的需求。因此,SharePoint也提供了一套非常完整的对象模型作为底层接口,以此为基础进行二次开发。
Windows SharePoint Services(以下简称WSS)作为SharePoint Portal Server(以下简称SPS)的基础部分,是在开发过程中使用最多的一套体系。因此,在本书开发部分的开始,使用一章的篇幅来介绍WSS的对象模型体系,以及一些简单的应用。
WSS提供了非常完善的一套对象模型体系,大致整个的Web服务器(SPWebServer类)、小到一个文件的版本信息(SPFileVersion类),以及一些网站的设置,都可以通过WSS对象模型来进行访问或修改。此外,为了弥补.NET类库在该环境中的一些不足,在SharePoint中也提供了一些常用的功能的函数,它们被封装在Microsoft.SharePoint.Utilities命名空间中。
通过使用SharePoint的对象模型,可以完成几乎所有的功能,但是在有些时候,由于SharePoint本身的限制(例如严格的权限控制),有一些功能仅使用对象模型是很难完成甚至无法完成的。所以,在考虑用户需求和设计方案的时候,也应该尽可能地考虑到实现的难易程度。
在WSS对象模型体系中,提供了如下一些命名空间(namespace):
- Microsoft.HtmlTrans.Interface
提供一个接口,用来将文档库中的某些文件以Html的形式显示到客户端,这样在客户端没有安装相应文件的浏览软件的时候,也可以查看这些文件;
- Microsoft.SharePoint
该命名空间是最常用的一个命名空间,其中提供了WSS中关于网站内容的基本的对象模型,例如网站、列表、文件和用户等,本章也主要是围绕这一命名空间进行介绍;
- Microsoft.SharePoint.Administration
该命名空间中主要提供了WSS网站管理和参数设置的一些类;
- Microsoft.SharePoint.Dsp
该命名空间以及之下的几个命名空间提供了一些WSS数据搜索用的接口;
- Microsoft.SharePoint.Meetings
该命名空间提供了对会议室网站进行操作的一些类;
- Microsoft.SharePoint.Security
该命名空间提供了WSS中自定义权限管理相关的类;
- Microsoft.SharePoint.SoapServer
该命名空间提供了关于WebPart和WebPart页相关的WebService类;
- Microsoft.SharePoint.Utilities
该命名空间提供了一些网站中常用的功能,主要是扩充.NET类库中的一些功能;
- Microsoft.SharePoint.WebControls
该命名空间提供了一些WSS中特有的Web控件类;
- Microsoft.SharePoint.WebPartPages
该命名空间提供了Web部件和Web部件页相关的类,其中Web部件(WebPart)是SharePoint开发中一个重点的环节,我们将在第11章中对其进行详细地叙述;
- Microsoft.SharePoint.WebPartPages.Communication
该命名空间提供了对Web部件通信的支持。
以上这些命名空间和类库封装在Microsoft.SharePoint.dll中。
由于篇幅的关系,在本章中只介绍最基本的一些对象模型的使用,只涉及到Microsoft.SharePoint这一命名空间。其他对象模型的使用方法请参照SDK。
为了便于实现和观察,也便于避开Web环境中一些复杂的机制和权限控制,本章和下一章的示例代码,均使用命令行(Console)方式完成。程序需要直接运行在装有WSS或SPS的服务器上,并且默认操作者具有网站管理员的权限。此外,本章和第10章着重讲解功能和某些注意事项,因此在介绍对象模型的时候,只介绍最常用的一些属性和方法,并且在每部分的最后给出一个示例说明该对象模型的使用方法。更全面的类库、属性和方法的介绍,以及更加详细的示例程序,请参考SDK中对应的章节。
本书中的代码均使用C#语言编写,在WSS或SPS环境中经过测试通过。
在绝大多数的WSS使用场景以及部分SPS的使用场景中,“网站”是使用得最多的一个对象,这是因为在WSS的体系结构中,几乎所有的内容(包括用户、列表、文件系统等)都是依附于网站之上的,这一点在对象模型中也能很明显地体现出来。
在WSS的结构中,网站被划分为Site(网站集)和Web(网站)这两种概念。
Site和Web的区别与联系
顾名思义,网站集是网站的集合体,在WSS中,Site的主要用处是管理网站,在对象模型中,Site所对应的SPSite除了网站的集合(SPWebCollection)外几乎不包含任何的信息,所有的信息都是储存在Web所对应的SPWeb这一对象模型中的,Web才是真正的内容承载者。
在SharePoint的最初设计理念中,将网站集称为Web,而网站称为Site,这一点从SDK中的SharePoint体系结构图中可以看出来。
但是,在设计对象模型的时候,却又将网站集的对象模型称为SPSite(即SharePoint Site),而网站的对象模型称为SPWeb。因此在SDK的代码示例中经常可以看到例如“SPSite web;”以及“SPWeb site;”这样的变量命名方法,这对于初学者来说是非常容易引起混淆的。
作为开发的参考,为了便于说明,以及和对象模型的统一,本书中所指的Site均为网站集的概念(对应于SPSite),而Web均为网站的概念(对应于SPWeb),请读者注意。
SPSite的使用
SPSite作为网站集对应的对象模型,其主要的用处是获取某个特定的网站,它最常用的几个功能如下:
构造函数
SPSite的构造函数有两种,分别以Site的url和Guid作为参数。
在SharePoint对象模型中,大部分对象都拥有一个Guid作为它唯一的标识符,通过这个Guid可以获取该对象的实例,例如Site(SPSite)、Web(SPWeb)、列表(SPList)、视图(SPView)以及SPS中的区域(Area)、门户列表(AreaListing)等。但也有一些是采用整型作为标识符的,例如列表项(SPListItem)、角色(SPRole)和用户(SPUser)等。
AllWebs属性
该属性是一个SPWebCollection类型的变量,通过这个属性,便可以获取到该网站集中的所有网站,包括一个顶级网站和它下面的所有子网站。然后通过以下三种形式之一,便可以得到某个特定的SPWeb的对象:
- webs[int index]:根据在该集合中的下标获取一个Web;
- webs[string url]:根据Web的相对url(相对于包含该网站的Site)获取Web;
- webs[Guid guid]:根据唯一标识该Web的guid获取。
在WSS对象模型中,集合(Collection)是一个比较重要的概念,它实际上是一种对象的存储方式(即.NET框架中集合的概念)。一般来说SPxxxCollection便是SPxxx这个类所对应的集合类,例如SPWebCollection、SPListCollection和SPFileCollection等。但是应该注意到的是,SPSiteCollection并不是包含在Microsoft.SharePoint命名空间中的类,而是在Microsoft.SharePoint.Administration这一命名空间中的,这也说明了Site的主要意义在于网站本身的管理,而非网站内容的管理。
RootWeb属性
该属性是一个SPWeb类型的变量,它所对应的对象是该网站集中的顶级网站,通过它可以逐步获得该网站级中的层级结构。(关于顶级网站和子网站的概念,请参考本书中“2.1.2Windows SharePoint 站点架构简介”部分。)
OpenWeb函数
该函数返回一个SPWeb类型的变量,通过该函数可以获得该网站集中一个特定的网站。它有以下三种使用形式:
- OpenWeb():在命令行模式中,该方法返回网站级中的顶级网站对象;但是在网络环境中使用该方法会有不同的效果,详见第11章11.3小节“WebPart编程中的对象模型”;
- OpenWeb(Guid guid):返回该guid所对应的网站对象;
- OpenWeb(string url):返回该url所对应的网站对象,注意该url为相对地址(相对于服务器根路径或者网站集根路径)。
【示例9-1】 SPSite的基本使用。
在这个示例中,展示了SPSite的基本用法,包括上面所提到的几个重要功能:
using System; using Microsoft.SharePoint; namespace WSSModelObject { class Example1_1 { [STAThread] static void Main(string[] args) { // 使用构造函数创建网站集对象 SPSite site = new SPSite("http://localhost"); // 获取根网站信息 Console.WriteLine("Root:" + site.RootWeb); // 遍历网站集中的所有网站 Console.WriteLine("All Webs in site:"); foreach(SPWeb web in site.AllWebs) { Console.WriteLine(web); } // 打开某个特定的网站 try { SPWeb web = site.OpenWeb("subweb1"); Console.WriteLine(web); } catch(Exception ex) { Console.WriteLine(ex.Message); } } } }
在编写程序的过程中,合理地使用try-catch语句是一种良好的编程习惯。SharePoint是一套相对庞大的对象模型体系,在编写程序的过程中,难免会出现预料之外的问题,因此应该尽可能对所有可能出错的语句进行try-catch,如果有必要,捕获每种特定的异常,并提供更加友好的出错信息,使得程序更加人性化。在本书中,为了节省篇幅,除非特殊的需要和说明,在后面的示例程序中一般不进行try-catch处理,请读者注意。
编写SharePoint的程序需要在引用中添加Microsoft.SharePoint.dll,如果是在安装了WSS的机器上,在VS.NET中添加引用界面选择Windows SharePoint Services即可,也可以将dll复制到其他的机器上再引用(但是仍然需要在装有WSS的机器上才能运行),该dll的默认安装路径为:C:\Program Files\Common Files\Microsoft Shared\web server extensions\60\ISAPI。在本书后续章节中除非特殊情况,不再使用完整的代码,而使用代码片段作为示例。
SPWeb的使用
在一般的应用场景下,SPWeb是使用最多的一个对象模型,因为几乎所有的WSS的内容都是依附于SPWeb对象的,在编程中也是使用SPWeb来获取其他的对象模型。而获取SPWeb对象的方法在本章9.2.2小节“SPSite的使用”中已经有所提及,就不在这里重复了。
大多数和WSS相关的内容都是通过使用SPWeb的一些成员变量来获取的,这些成员变量主要有:
- AllUsers:网站内的所有成员,以及通过域组(domain group)来浏览网站的用户;
- Files:网站下的所有文件;
- Folders:网站下的所有目录;
- Groups:所有跨网站用户组;
- Lists:网站下的所有列表;
- ListTemplates:网站下的所有列表模板;
- Permissions:网站下的权限;
- Roles:网站下的所有角色;
- Users:属于该网站的所有用户;
- Webs:该网站的所有子网站。
通过使用这些成员变量,就可以获取到相应内容的对象集合(Collection),进而获取需要的内容。
此外,SPWeb的某些成员变量对应于该网站的一些属性,例如:
- AllowAnonymousAccess:网站是否允许匿名访问(只读);
- Author:网站的创建者(只读);
- Created:网站的创建时间(只读);
- CurrentUser:当前的用户(只读);
- ID:唯一标识该网站的Guid(只读);
- IsRootWeb:该网站是否为顶级网站(只读);
- ParentWeb:该网站的父网站(只读);
- Site:该网站所属的网站集(只读);
- Title:该网站的标题;
- Url:该网站的url(绝对路径)(只读);
- WebTemplate:该网站的模板(只读)。
SPWeb对象还提供了一些方法,例如:
- GetFile:通过url获取一个文件的对象(SPFile);
- GetFolder:通过url获取一个目录的对象(SPFolder);
- GetListOfType:获取特定类型的列表的集合;
- GetSubwebsForCurrentUser:获取该网站的子网站(可以指定模板);
- GetViewFromUrl:通过url获取一个列表的视图(SPView);
- SaveAsTemplate:将网站保存为模板;
- SearchDocuments:搜索网站的文档库(需要开启全文检索功能);
- SearchListItems:搜索列表条目;
- Update:使网站属性的修改生效。
在SharePoint的对象模型中,一些比较重要的对象都会拥有Update方法(例如SPWeb、SPList、SPField和SPListItem),在修改这些对象的属性时,只有在调用Update方法之后,这些修改才会真正生效。仅限普通属性,不包括集合类的属性,比如SPWeb.Lists中添加或删除一个列表,不需要调用SPWeb.Update方法。这一点需要特别引起注意 。
【示例9-2】 得到一个网站集中的所有网站,并输出它们的标题、url、父网站及子网站。
SPSite site = new SPSite("http://localhost"); foreach(SPWeb web in site.AllWebs) { Console.WriteLine("Title: " + web.Title); Console.WriteLine("Url: " + url); Console.WriteLine("ParentWeb: " + web.ParentWeb); Console.Write("SubWebs: "); foreach(SPWeb subweb in web.Webs) Console.Write(subweb.ToString() + " "); Console.WriteLine(); }
一个小技巧:在.NET对象模型中,每个类都会有ToString函数(继承自Object类),一般来说每个类也都会对这个方法进行重写。SPWeb的ToString方法一般情况下就是返回了SPWeb.Title这个属性。在大多数字符串操作过程中,一个对象的ToString方法是可以被隐式调用的(例如示例9-1中就使用了这个特性),在不知道该对象是否为空(null)的时候,如果显式调用ToString方法会造成一个异常(NullReferenceException),但是在隐式调用的时候便不会产生这个异常,如果仅是作为输出的需要,隐式的调用要比显式的调用更加方便。
在示例9-2中,输出每个网站的父网站,但是对于顶级网站来说,其父网站为空,如果显示调用的话,便会出现异常,采用隐式调用就可以避开这个问题,只显示一个空的字符串。
示例9-2中使用了三种输出网站标题的方法:SPWeb.Title属性,隐式调用SPWeb.ToString方法,显式调用SPWeb.ToString方法。
列表相关的对象模型
在SharePoint中,列表(List)是一个非常强大的功能。它可以方便地自定义列表的结构,添加和删除各种类型的字段,也可以设置计算字段和引用字段,也可以设置列表条目的审批功能,同时列表还提供了多种可以自定义的视图,对列表的数据进行筛选或者排序。本节主要介绍列表相关的对象,包括列表(SPList)、列表视图(SPListView)、列表字段(SPField)和列表条目(SPListItem)。
SPList的使用
在使用列表的功能之前,通常都需要首先获取该列表对象,获取SPList的主要方法是通过访问SPWeb.Lists这一SPListCollection类型的属性。从该集合中获得一个特定的列表对象有如下三种方法:
- lists[string name]:通过该列表的名称获取;
- lists[Guid guid]:通过唯一标识该列表的Guid获取;
- lists[int index]:通过列表在该列表集合中的下标来获取
在网站上添加列表,也是通过SPListCollection对象来完成的。添加一个列表通过调用SPListCollection.Add方法来完成,创建成功之后,会返回新列表的Guid。该方法提供了如下三种形式:
- Add(string title, string description, SPListTemplate template):
前两个参数分别指定列表的名称和简介,第三个参数是一个SPListTemplate型变量,指定该列表创建时所需要的列表模板对象,该对象可以通过SPWeb.ListTemplates属性获得;
- Add(string title, string description, SPListTemplateType type):
前两个参数指定列表的名称和简介,第三个参数使用SPListTemplateType型枚举指定列表模板,枚举中所包含的都是网站默认拥有的基本类型的列表模板,如果要创建一个自定义的列表,请使用SPListTemplateType.GenericList作为该参数;
- Add(string title, string description, SPListTemplate template, SPDocTemplate docTemplate):
该方法会创建一个文档库(一种特殊的列表),前两个参数分别指定列表的名称和简介,第三个参数制定列表的模板对象,第四个参数指定文档库的模板对象,该参数是一个SPDocTemplate类型的变量,可以通过SPWeb.DocTemplates属性获得。
删除列表时,通过调用SPListCollection.Delete方法来完成,该方法只有一种形式:
- Delete(Guid guid):通过列表的Guid删除该列表。
SPList类有如下一些常用的属性:
- BaseTemplate:该列表所对应的列表模板(只读);
- BaseType:该列表的基础类型(只读);
- DefaultView:该列表的默认视图对象(只读);
- EnableAttachments:该列表是否允许添加附件;
- EnableModeration:该列表是否开启审批功能;
- Fields:列表字段的集合(将在下文进行详细介绍);
- Forms:列表表单的集合,主要有浏览、添加和修改几个页面(只读);
- ID:标识该列表的唯一的Guid(只读);
- Items:列表条目的集合(将在下文进行详细介绍);
- ParentWeb:列表所在的网站对象(只读);
- Title:列表的标题;
- Views:该列表的视图的集合(将在下文进行详细介绍)(只读)。
这其中值得注意的是BaseTemplate与BaseType的区别:BaseTemplate是生成列表的模板,例如“链接”和“联系人”等,每个模板中都默认设置了一些独有的字段,该属性为SPListTemplateType型的枚举类型,默认这些模板的字段设置可以在SDK的“Field Tables for Default Lists”一节中找到;它的具体位置为Microsoft Windows Share Point Services?Appendix?Field Tables for Default Lists,而BaseType则是列表的基础类型,例如“讨论区”、“文档库”等,每种基础类型的列表都提供了一些普通列表所不具备的特殊的功能,该属性为SPBaseType型的枚举类型。
修改列表属性后,通过调用SPList.Update方法使修改生效。
【示例9-3】 在该示例中创建一个联系人列表,并显示该列表添加条目页面的url。
// 首先获取到SPWeb对象web SPListCollection lists = web.Lists; SPList newList = null; try { Guid id = lists.Add("DemoList", "这是一个测试列表", SPListTemplateType.Contacts); newList = lists[id]; SPForm form = newList.Forms[PAGETYPE.PAGE_NEWFORM]; Console.WriteLine(form.Url); } catch { Console.WriteLine("列表添加失败"); }
SPView的使用
视图在SharePoint的列表中是一个比较重要的概念,在SharePoint中,列表中所有的数据都是通过视图呈现给用户的,视图中定义了需要显示的字段,以及显示的方式,某一些特殊的列表默认拥有一些特殊的视图将数据呈现出来,例如“任务”模板列表中的“日历视图”,等等。
除了负责数据的多样化显示,视图的另外一个重要的作用就是对数据的筛选和排序,在SharePoint环境中可以直接对视图的这些内容方便地进行修改,通过使用计算字段,可以更加丰富筛选和排序的功能。
获取一个SPView对象有如下几种方法:
- 通过List.DefaultView属性得到该列表的默认视图;
- 通过SPWeb.GetViewFromUrl方法根据url获取到该视图,在实际使用中,可以使用这种方法先获得一个视图,再得到这个视图所在的列表的对象;
- 通过List.Views得到该列表的所有视图,再通过以下三种方式得到特定的视图:
- views[string name]:通过视图的名称获取;
- views[Guid guid]:通过唯一标识该视图的Guid获取;
- views[int index]:通过视图在该视图集合中的下标来获取。
添加一个视图通过调用SPViewCollection.Add方法来完成,该方法有两种形式:
- Add(string name, StringCollection fields, string query, uint rowLimit, bool paged, bool makeDefault):
name参数指定了视图的名称,fields参数指定了需要显示的字段名的集合,query参数指定了对数据的筛选条件,rowLimit参数指定了视图中一次所返回的列表条目的最大个数,paged参数指定了该视图是否支持翻页,makeDefault参数指定了是否需要将该视图作为默认视图;
- Add(string name, StringCollection fields, string query, uint rowLimit, bool paged, bool makeDefault,
- SPViewCollection.SPViewType type, bool personalView):
前面的参数含义与上文相同,type参数指定了该视图的基本类型,personalView参数指定了该视图是否为个人视图(否则为公共视图)。
需要注意的是,与列表的添加方法不同,视图的添加方法返回的对象是SPView的对象,而不是一个Guid。
删除一个视图同样使用SPViewCollection.Delete方法,用视图的Guid作为参数。
有一点需要注意的是,在使用默认页面浏览一个视图的时候,视图的翻页功能只有“下一页”而没有“上一页”,如果需要实现向前翻页的功能,需要自己编写程序来完成。
SPView中常用的一些属性如下:
- ID:标识该视图的唯一的Guid;
- ParentList:包含该视图的列表对象(SPList);
- PropertiesXml:该视图的基本信息,包括url、名称和类型等(只读);
- Query:视图中对数据进行筛选的查询xml字符串;
- SchemaXml:该视图的信息,包括基本信息和例如筛选、分组等的设置(只读);
- Title:该视图的名称;
- ViewFields:该视图需要显示的字段的集合;
- Url:显示该视图所对应的url(只读);
修改视图属性后,使用SPView.Update方法使修改生效。
【示例9-4】 该示例中创建了一个视图,并指定了该视图的一些设置:
// 首先获取到SPWeb对象web SPList list = web.Lists["ListName"]; SPViewCollection views = list.Views; string viewName = "View_Name"; StringCollection viewFields = new StringCollection(); viewFields.Add("Field1_Name"); viewFields.Add("Field2_Name"); viewFields.Add("Field3_Name"); string query = "<Where><Eq><FieldRef Name=\"Field3_Name\"/>" + "<Value Type=\"Text\">Text</Value></Eq></Where>"; views.Add(viewName, viewFields, query, 100, true, false);
程序中的StringCollection类是在System.Collection.Specialized命名空间中。
SPField的使用
SPField对应于列表对象中的字段(Field)对象,和传统的数据表一样,SharePoint的列表也是由若干个字段所组成的,每个字段可以设置为不同的数据类型,也可以拥有不同的属性设置(例如默认值、是否隐藏、是否可以为空等)。而SharePoint列表的最大一个特点,就是字段的可定制性,不需要进行任何的编程,也不用深入数据库进行复杂的调整,仅在使用界面上就可以方便地对列表的字段进行添加、删除和修改,这种方便的特性也正是很多用户喜爱SharePoint的一个重要原因。
获得一个SPField对象的方法主要是通过SPList.Fields属性得到所有字段,再通过以下两种方法得到特定字段的对象。
- fields[string dispName]:根据该字段的显示名称获得
- fields[int index]:根据该字段在集合中的下标获得。
为列表添加一个字段有三种方法:
- Add(string dispName, SPFieldType type, bool bRequired)
其中第一个参数指定该字段的显示名称,第二个参数指定该字段的类型,第三个参数指定在填写数据的时候,该字段是否为必填内容。
- AddLookup(string dispName, Guid lookupListID, bool bRequired)
该方法为列表添加一个特殊的字段——“查阅项”字段,通过第二个参数指定目标列表的Guid,其余两个参数的含义和使用方法与Add方法相同。
- AddFieldAsXml(string strXml)
通过一段xml的描述添加一个字段,该描述中需要包括字段等信息,实际上,这段xml描述对应于SPField.SchemaXml属性。
需要特别注意的是,以上三种方法所返回的虽然都是string型的变量,但是它们的含义各不相同,Add方法返回的是显示名称,AddLookup方法所返回的是内部名称(这两者的区别稍候会进行介绍),而AddFieldAsXml方法所返回的是一段包含字段名称的xml。
注意:在添加字段时,bRequired参数(对应与SPField.Required属性)指定的是在用户界面中新建、修改列表项的时候,该字段是否为必填内容。但实际上,如果我们通过对象模型来创建或修改一个列表条目的时候,该字段并不会起到任何限制作用。
SPField拥有如下一些比较常用的属性。
- DefaultFormula:计算字段的公式;
- DefaultValue:字段的默认值,即该字段在未进行设置时的初始值;
- Description:该字段的说明描述信息;
- Filterable:该字段是否可以被筛选(只读);
- Hidden:该字段是否在列表中显示;
- InernalName:该字段的内部名称;
- ParentList:该字段所在的列表的对象;
- ReadOnlyField:该字段是否被只读;
- Required:在填写数据的时候,该字段是否必填;
- SchemaXml:该字段设置的信息;
- Sortable:该字段是否可以被排序;
- Title:该字段的字段名,即显示名称;
- Type:该字段的类型,为SPFieldType类型的枚举。
在SharePoint中,每一个字段都有两个名称,即显示名称(DisplayName)和内部名称(InternalName),它们在对象模型中对应于SPField.Title和SPField.InternalName。其中显示名称是在用户使用界面上看到的名称,虽然该名称在网站使用界面的操作中是不可重复的,但是,在使用对象模型添加字段的时候,或者内部管理的时候,可能会有一些重名的字段(其中典型的代表就是每个列表的“标题”字段);而内部名称是SharePoint列表用于内部管理的名称,它在列表中是唯一的,而且其中没有中文和空格(在保存为内部名称时,对于这些字符会进行编码)。
在编写程序的时候下列情况中必须使用显示名称:
- 使用SPList.Fields["name"]获取该字段对象时,必须通过显示名称。
在下列情况中必须使用内部名称:
- 使用SPView.ViewFields的时候,添加、删除都是通过内部名称,获取的时候也是得到内部名称;
- 使用SPView.Query的时候,必须使用内部名称;
- 使用SPQuery(下面会提到该类)的时候,必须使用内部名称。
在下列情况中即可以使用显示名称,也可以使用内部名称:
- 使用SPListItem["fieldName"]获取或设置列表项某个字段的值。
上面所提到的一些属性是SPField类中的属性,也就是所有字段都拥有的一些属性,而SharePoint对象模型中,也为每一种类型的字段提供了单独的类,例如SPFieldText、SPFieldLookup和SPFieldNumber等,每一个类都有一些该类型的字段所拥有的特殊属性,这些类是SPField的子类,在使用的时候需要通过强制类型转换,将SPField类转换为对应的类型。这些类的具体使用方法由于篇幅原因不在此进行详细地介绍,请参考SDK中的有关内容。
在使用SchemaXml属性的时候,我们会发现除了SPField以及它的子类所包含的一些属性之外,还会有一个“ColName”属性,实际上这个属性是和SharePoint列表实现的具体机制相关的,它保存的是在底层数据库的某个表中存放该字段那一列的名称。关于这一点,会在第12章高级开发中,进行比较详细的介绍。
修改字段的属性后,通过调用SPField.Update方法使修改生效。
【示例9-5】 为列表创建一个NumDemo字段,并指定该字段的最大值和最小值:
// 首先获取到SPWeb对象web SPList list = web.Lists["ListName"]; string fieldName = list.Fields.Add("NumDemo", SPFieldType.Number, false); SPFieldNumber field = (SPFieldNumber)list.Fields[fieldName]; field.MinimumValue = 0; field.MaximumValue = 100; field.Update();
该示例中值得注意的是,在列表的字段集合中添加一个字段之后,没有调用list.Update方法,而在对字段本身的属性进行修改之后,调用了field.Update方法。关于对象模型中Update方法的这一点特性已经在本章9.2小节中进行说明了,在此通过示例的方式再次强调一下。
SPListItem的使用
在列表的实际操作中,最终要接触到的还是作为数据内容部分的列表条目(List Item)。一般来说,在访问列表的某个具体条目之前,都需要先获得一个列表条目的集合,在SharePoint对象模型中,提供了很多种方法来获取列表条目集合:
最直接地获取列表条目的方法为,使用SPList.Items属性,该属性返回列表中的所有列表条目。在需要得到或者遍历所有列表条目的时候,可以使用这种获取列表条目的方法。
如果有目的地要获得部分列表条目,可以使用SPList.GetItems方法,该方法有如下三种形式:
- GetItems(SPView view)
返回指定视图中的列表条目,通过这种方法可以按照视图中所指定的筛选、排序及其他的条件按照顺序返回列表条目。在返回的条目中,也只有在视图中定义过的可查看字段中的数据才可以访问到。
- GetItems(SPQuery query)
顾名思义,SPQuery是SharePoint中负责查询列表条目的一个类,通过定义一个查询,可以方便地获取想要得到的列表条目,SPQuery提供了两种构造函数,一种是无参数的,另外一种可以带有一个SPView类型的参数,即在指定的视图上进行二次的查找。 SPQuery最核心的一个属性就是Query属性,它是一个字符串的类型,它通过一种特殊定义过的xml形式,即CAML(Collaborative Application Markup Language)的形式描述一个查询的条件,实际上,这个查询字符串和SPView.Query属性是相当的。在SPQuery中,也可以通过ViewFields属性来指定需要查看的字段(如果不加以指定,则查看所有字段)。在本节最后的示例中,将演示SPQuery的用法。
- GetItems(SPQuery query, string viewID)
指定SPQuery查询和视图,获取列表条目。需要特别注意的是,虽然第二个参数为字符串类型,但是在使用的时候需要传入的是列表视图的Guid,而不是视图的名称,而且该Guid要以一种特殊的形式传入,即两边用“{}”包围起来,全大写形式,这种形式可以通过Guid.ToString("B").ToUpper()方法得到。
在使用SPQuery的时候,必须每使用一次都要重新进行构造(即使用new运算符重新生成一个新的对象),然后再指定Query属性。否则,如果不进行重新构造,即使指定了不同的Query属性,在每次查询的时候始终得到的是第一次指定的Query条件的查询结果。这一点非常容易被忽略。
以上几种方法所返回的都是SPListItemCollection类型的列表条目集合,获得该集合后,在获得某个具体的列表条目时,有下面两种方法。
- items[int index]:通过在集合中的下标得到该条目,这种方法多在遍历集合的时候使用;
也可以使用SPListItemCollection.GetItemById方法。
- GetItemById(int id):在SharePoint中,每个列表条目都会有一个在该列表中唯一的id(int型),调用SPListItemCollection类的GetItemById方法,就可以通过该id来得到对应的列表条目。
在得到列表条目之后,就可以对该条目的内容进行访问或修改了,访问条目某个字段的方法最常用的方法为:
- item[string fieldName],其中fieldName可以使用该字段的显示名称,也可以使用该字段的内部名称。
还有一点需要注意的是,该方法所返回的是一个Object类型的变量,如果需要使用该变量的话,必须要对它进行强制类型转换,在转换的时候也要特别注意,如果该条目的该字段没有填写任何内容,那么该返回值是null,如果不加以检查就进行类型转换的话,会引发一个异常(NullReferenceException)。在使用这种方法填写或修改字段数据的时候,除了DateTime类型的数据之外,可以一律使用string类型写入(但是除非特殊需要,不建议使用这种做法)。
审批也是SharePoint列表的一个重要的特色,它允许一个列表条目呈现“已审批、待定、被拒绝”这三种状态,在默认视图中,只显示已审批的条目,在“我的提交”视图和“审批视图”中,可以看到其他的条目。
在SharePoint中,一个列表条目的审批信息并非是保存在某个字段中的,而是在对象模型中对应为SPModerationInformation类,并通过SPListItem.ModerationInfomation属性来访问,该类只有两个属性。
- Comments:审批意见。即列表管理员进行审批操作的时候所填写的意见。
- Status:审批状态。该属性为SPModerationStatusType枚举类型,对应三种状态。
需要注意的是,ModerationInfomation这一属性,只有当列表允许审批的时候(即列表SPList的EnableModeration属性为true的时候)才可以取得,否则,该值始终为null。
在使用允许审批的列表的时候,获取列表条目时会有一些不同。使用SPList.Items属性只能获得该列表中状态为“已通过”的那些列表条目,要获得其他条目,则必须通过“我的提交”或“审批视图”这两个视图,使用SPList.GetItems方法来取得。开启了审批的列表都会有这两个视图存在,这两个视图SPView对象的ModerationType属性分别为“Contributor”和“Moderator”,表明属于哪一个审批的视图。
在SPListItem中,还有一些比较常用的属性如下。
- Attachments:该列表条目的附件集合;
- File:如果该列表是文档库的话,得到该文件的对象(以上两个属性的使用请参考下一节“文件相关的对象模型”);
- ID:在该列表中唯一标识该列表条目的整型的id;
- ModerationInfomation:该列表条目的审批信息;
- ParentList:该列表条目所在列表的对象;
- Xml:以Xml的格式返回该列表条目中的所有数据。
在列表条目的内容修改后,通过调用SPListItem.Update方法使修改生效。
添加一个列表条目的方法非常简单,只需要调用SPListItemCollection.Add方法,该方法不需要参数,直接返回一个空的SPListItem对象,通过对该对象对各字段的内容进行修改,再调用Update方法,即可将该条目添加到该列表中。
删除一个列表条目,有两种方法:
- SPListItemCollection.DeleteById(int id)
通过列表条目的id来删除该条目;
- SPListItemCollection.Delete(int index)
通过集合中的下标来删除该条目。
在通过Delete方法删除一个列表中的所有条目时,注意必须使用下面这种逆序的循环方法:
int total = items.Count; for(int i=total-1; i>=0; i--){ items.Delete(i); }
而不能正向的循环,更不能使用foreach循环来进行,在初学者中,这是一个比较常见的错误。请读者自己思考这样做的原因。
在SPListItemCollection类中,还有一个非常有用的方法:GetDataTable方法,即:
DataTable GetDataTable();
该方法可以返回由这些列表条目所组成的DataTable对象,以便将数据绑定到一些显示控件(如DataGrid)上。但是注意当列表中没有条目的时候,该函数返回的是null,而不是一个有效的DataTable对象。
【示例9-6】 通过SPQuery获得Score字段中大于等于60的列表条目,并且在这些条目的标题后加上“(合格)”字符串,然后再另一列表中,添加一个新条目,写入合格人数。
// 首先获取到SPWeb对象web SPListCollection lists = web.Lists; SPList scoreList = lists["Score"]; SPList passList = lists["Pass"]; SPQuery query = new SPQuery(); query.Query = "<Where><Geq><FieldRef Name='Score'/>" + "<Value Type='Number'>60</Value></Geq></Where>"; SPListItemCollection items = scoreList.GetItems(query); foreach(SPListItem item in items) { string title = item["Title"] + "(合格)"; item["Title"] = title; item.Update(); } SPListItem newItem = passList.Items.Add(); newItem["Count"] = items.Count; newItem.Update();
在该例中,为了简化场景,没有考虑到不同人、不同科目的分数问题。另外,这个例子只是为了说明和列表条目有关对象模型的使用方法,在实际的应用场景中,类似于上面这种问题,可以通过视图的筛选、分组和汇总的功能在一张列表中直接完成,而且可以接受多人、多科目这种条件,分别统计每一科的合格人数,不需要进行任何编程,SharePoint中强大的视图功能便可以体现在其中。请读者自己思考视图设置的方法。
文件相关的对象模型
SPAttachmentCollection的使用
在SharePoint的列表中,每个列表条目可以拥有0到多个附件文件(附件功能可以在列表常规设置中开启或关闭),在对象模型中,访问这些附件,则可以使用对象模型中的SPAttachmentCollection类来完成。
使用SPAttachmentCollection.Count属性可以得到该列表条目中附件的个数,使用以下方法,则可以获得每一个附件所在的地址。
- attachments[int index]:通过下标得到附件的文件名,这些附件实际上也是保存在SharePoint的文件系统中的,它们的url为:“List/Attachments/ItemID/FileName”,自然地,SPAttachmentCollection的对象模型中也提供了这样一个属性来访问这一串地址:
- UrlPrefix:附件文件的前缀url地址(绝对url)。
附件的添加和删除,和添加、删除文件的方法是一样的。
- Add(string filename, byte[] data):第一个参数指定文件名,第二个参数指定附件内容的字节流。该文件已经存在的时候,也会返回一个异常。
- Delete(string filename):根据文件名删除该附件。
与添加、删除文件不同的是,因为附件操作是包含在列表条目的修改之中,所以使用Add方法和Delete方法必须调用SPListItem.Update方法才能使修改生效。为了更直接的对附件进行操作,免除Update这一麻烦,SPAttachmentCollection类中提供了AddNow和DeleteNow两个方法,它们的参数和使用与Add和Delete方法一致,只是调用完之后立刻生效,而不再需要进行Update。
在一个列表条目生成之前,SPListItem中的一切属性都是不可用的,所以在对附件进行操作的时候尤其要进行注意,只能对已有的列表条目进行附件的操作。在添加一个新的列表条目的时候,也必须先执行SPListItem.Update,使之成为已有的列表条目,然后才能进行附件操作。
【示例9-9】 该示例读取DemoList列表第一个列表条目的附件,并将它们保存到本地:
// 首先获取到SPWeb对象web SPList list = web.Lists["DemoList"]; SPListItem item = list.Items[0]; SPAttachmentCollection attach = item.Attachments; for(int i=0; i<attach.Count; i++) { String url = attach.UrlPrefix + attach[i]; Console.WriteLine("正在下载{0}...", url); SPFile file = web.GetFile(url); FileStream fs = new FileStream(file.Name, FileMode.Create); byte[] content = file.OpenBinary(); fs.Write(content, 0, content.Length); fs.Close(); }
注意在该程序中,默认列表DemoList存在,也默认该列表中拥有至少一个列表条目。
文档库
文档库是SharePoint中非常重要的一个功能,它提供了例如签入/签出,结合Microsoft Office在线编辑、版本控制等诸多方便的功能。而在SharePoint的对象模型中文档库也是一个比较特殊的对象。
在SharePoint中,文档库有三种形式:文档库、表单库、图片库。
作为一个特殊的对象,文档库即是一个列表(List),也是一个文件夹(Folder)。这样的特性就意味着文档库既可以通过SPList对象来访问,也可以通过SPFolder和SPFile来访问,它们之间是有着内在联系和明确分工的。
在使用SPList访问的时候,它的“FileLeafRef”(内部名称)字段保存的是文件的文件名,它可以通过定义视图和查询来查找我们所需要的某部分文件。在获得SPListItem之后,也可以通过SPListItem.File来得到该列表条目所对应的文件(SPFile)的对象。但是由于是列表的形式,在获得列表的时候是很按照文件夹的方式去获取的,这个时候就需要结合另外的类来进行操作。
判断一个列表是否是文档库,可以通过判断SPList.BaseType属性是否为SPBaseType.DocumentLibrary来完成。而SharePoint也专门提供了一个SPList的子类——SPDocumentLibrary来访问文档库,在判断一个列表为文档库之后,可以将该对象强制转换为SPDocumentLibrary类型,在该类型中,提供了一个有用的函数:
- GetItemsInFolder(SPView view, SPFolder folder):指定一个列表的视图,指定一个文件夹,返回该文件夹内的文件所对应的列表条目集合对象(SPListItemCollection)。
同时,我们也可以通过SPList.RootFolder属性得到该文档库的根目录的对象(注意之前应把SPListCollection.IncludeRootFolder设为true)。
在使用SPFolder和SPFile对象访问文档库的时候,可以方便地获取文档库中的层级结构,也可以得到文件的签入/签出状态和版本控制信息,也可以方便地对文件进行复制、移动和删除的操作。但是仅使用这种方法,却无法获得一个文档的审批状态。
在判断文件夹是否为文档库时,可以通过SPFolder.ContainingDocumentLibrary属性来完成,如果该文件夹在文档库中,那么该属性会返回该文档库所在列表的Guid,可以借此获得列表对象;在判断一个文件是否在文档库中时,使用SPFile.InDocumentLibrary属性即可。在确定一个文件包含在文档库之后,通过SPFile.Item属性就可以得到对应的列表条目对象(SPListItem)。
将SPFolder/SPFile与SPDocumentLibrary结合起来使用,可以充分地发挥SharePoint文档库的强大功能。此外,SharePoint文档库还提供了文档讨论的功能,通过ie的一个ActiveX插件来对每一篇文档进行讨论,在对象模型中也提供了SPDocDiscussion类获得该讨论的部分信息,有兴趣的用户可以参考SDK中的相关章节。
在使用文档库的时候,尤其是在中文SharePoint系统中,特别需要注意的是,要明确“列表名称”和“目录名称”这两个不同的概念,这两者可能是不同的,例如,一个文档库的名称叫做“共享文档”(列表的名称),而它所在的url是“Shared Document”(目录的名称)。在使用SPList和SPFolder的时候,不要将这两者混淆起来。
用户/权限相关的对象模型
权限系统是SharePoint的另一大特点,在WSS中,权限可以划分到列表级,而且SharePoint的权限是详细到代码级别的,称为CAS(Code Access Security),也就是说每一个对象模型中的方法、属性的访问都会涉及到权限的问题。这也是为什么前两章都要使用命令行(Console)方式的程序作为示例,而且直接在服务器端运行的原因(正如本章一开始所说的,默认读者是以管理员的身份在服务器端进行操作)。在这样一种权限的机制上,应该说整个SharePoint环境是比较安全的,除非直接读取底层数据库,否则用户无法获得其权限之外的数据;然而在另一个角度上,这种权限的机制也比较死板,只要数据在用户的访问或修改权限之内,那么使用普通的方法也是无法真正限制用户对数据的访问和修改的。
而在用户系统上,SharePoint可以与AD相结合,通过AD来管理、组织用户,可以说非常灵活和强大。
一般来说,用户系统与权限系统是比较紧密地结合在一起的,SharePoint也不例外。因此,本节将两者结合起来介绍。SharePoint对象模型中与用户/权限相关的类主要有以下三个:
SPPermission、SPRole、SPUser。
SPPermission的使用
在SharePoint中,由于权限是深入到代码级别的,在每执行一句代码——尤其是对数据进行修改、对系统进行管理的代码——的时候,都有可能会因为当前执行者的权限不足而引发异常。虽然try-catch能够在事后检测并捕获到大部分这种异常,但是,事前的检测在代码编写的过程中有时也是必要的;而有的时候,也需要根据用户的不同权限显示出不同的信息。用户权限的检测就是通过SPPermission类来完成的。
在介绍SPPermission类之前,有必要先简要介绍一下和权限相关的重要的枚举类型SPRights。在这个枚举类型中,列举了所有WSS网站中所用到的权限,例如创建列表条目、修改列表条目、删除列表条目等。在使用这些权限的时候,可以通过二进制掩模(Mask)的方式,将多个权限进行或(or)操作,得到一个新的包含所有用户指定的权限的SPRights变量,后文中的PermissionMask一般都是通过这种方法获得的。由于篇幅关系,这些具体的权限及其含义就不在此列出了,需要使用的时候,请读者参考SDK中的相关内容。
另外,SharePoint也提供了SPPermissionGroup枚举类型,其中定义了每种角色的PermissionMask,在需要获取角色默认权限的时候,可以直接使用该枚举类型。
权限都是挂靠在某个对象上的(比如网站、列表等),在访问这些对象的权限的时候,可以直接通过SPWeb.Permissions属性和SPList.Permissions属性来获得。获取某个具体的用户、角色的权限的时候,通过以下方法来取得:
- permissions[SPMember member]
其中SPMember是表示用户的SPUser类、表示角色的SPRole类、表示用户组的SPGroup类的一个父类。通过这种方式,可以获得某个网站(或列表)上,某个用户(或角色)的权限。
添加、删除某个用户的权限的时候,同样通过SPPermissionCollection类的方法来完成:
- Add(SPMember member, SPRights permissionMask):为某个网站成员(用户或角色)添加permissionMask中指定的权限;
- Remove(SPMember member):删除指定网站成员的权限;
- ResetPermissions():按照父网站的权限设置,重置该对象的权限。
在得到一个SPPermission对象之后,可以使用它的一些属性:
- Member:一个SPMember的对象,即拥有该权限的成员;
- Parent:一个Object的对象,即拥有该权限的对象(SPWeb或SPList);
- PermissionMask:具体的权限设置;
- Xml:以xml形式描述的权限设置。
通过将PermissionMask属性与SPRights枚举中的某些具体权限进行与(and)操作,根据操作结果是否非零,来表明该成员在该对象上是否拥有该权限。
但是,正如本节一开始所提到的,之所以需要检查权限的设置,是因为有一些用户没有权限来进行数据的操作或系统的设置。而上面所涉及到的那些方法和属性所需要的对于权限的控制的权限,显然是“普通用户”所不具备的。好在SharePoint为我们提供了一个“普通用户”也可以执行的方法,用来检测权限,它是SPPermissionCollection中的一个方法:
- DoesUserHavePermission(SPRights permissionMask)
检测当前的用户是否具有参数中所描述的权限,该方法返回一个bool型的值。在执行某些语句之前,或者在需要针对不同权限用户显示不同内容的时候,通过调用这个方法,就可以明确地知道当前执行这段代码的用户,是否具有某种权限,从而再进行相应的处理。
【示例9-10】 列举某个网站上当前用户的所有权限:
// 首先获取到SPWeb对象web foreach(SPRights right in Enum.GetValues(typeof(SPRights))) { if(web.Permissions.DoesUserHavePermissions(right)) { Console.WriteLine(right.ToString()); } }
读者可以使用不同的网站用户身份登录服务器运行这段代码,观察得到的结果有何不同。
SPUser的使用
SPUser是SharePoint中的用户类,在获取SPUser对象的时候,可以通过SPWeb.Users、SPWeb.AllUsers或者SPRole.Users来得到一个SPUserCollection,再通过以下两种方式得到用户。
- users[string loginName]:以登录名获取到集合中的用户;
- users[int index]:以集合中的下标获取到用户。
也可以使用如下方法。
- GetByID(int id):通过用户id获取某个用户的对象;
- GetByEmail(string email):通过用户的电子邮件地址获取某个用户的对象。
如果只需要获取到当前用户的话,也可以方便地使用SPWeb.CurrentUser属性。
为某个集合添加、删除用户的时候,使用SPUserCollection类中的方法。
- AddCollection(SPUserInfo[] users):添加一批用户,其中SPUserInfo是一个简单的结构,其中包含Email、LoginName、Name和Notes这四个属性,属性的含义见SPUser类的属性;
- Remove(int index):通过集合中的下标来删除集合中的用户;
- Remove(string loginName):通过用户的登录名来删除该用户;
- RemoveByID(int id):通过用户的id来删除该用户;
- RemoveCollection(string[] loginNames):通过登录名删除一批用户。
SPUser有如下几个常用的属性。
- Email:用户的E-mail地址;
- ID:在当前Site上,唯一标识该用户的id(int型)(只读);
- IsDomainGroup:该用户是否是一个域组(只读);
- IsSiteAdmin:当前用户是否是网站管理员(只读);
- LoginName:用户的登录名(只读);
- Name:用户的显示名称;
- Notes:用户的简要说明;
- ParentWeb:该用户所在的网站(只读);
- Roles:该用户在该网站的角色;
- Xml:该用户信息的xml形式的描述(只读)。
需要值得注意的是,在上述的用户信息中,只有LoginName是唯一的(也是全局唯一的),在不同的网站上,用户可能拥有不同的E-mail、显示名称和简介。
在修改用户的属性之后,需要调用SPUser.Update方法使修改生效。
为用户添加角色的过程,一般而言,是通过在角色中加入该用户来完成的,将在下一部分介绍这一方法。
SPRole的使用
SPRole对应于WSS网站中的用户角色(也称为网站用户组,即Site Group)。首先要特别提醒读者注意的是,该对象模型只能应用于WSS网站中,在SPS网站中使用该对象,则会直接引发错误,并且该错误无法被try-catch所捕获,请特别加以小心。
获取SPRole的对象,一般也是先通过SPWeb.Roles属性或者SPUser.Roles属性得到一个SPRoleCollection对象,再通过以下两种形式得到特定的SPRole。
- roles[string name]:通过角色的名称获取;
- roles[int index]:通过集合中的下标获取;
或者使用如下方法。
- GetByID(int id):通过角色的id获取;
- GetSpecialRole(SPRoleType type):一般来说,网站会默认的拥有一些特殊的角色(管理员、网站设计者、讨论参与者、读者和来宾),在对象模型中,SPRoleType枚举类型对应这五种已有的角色。该方法可以直接获得这五种特殊的角色之一。
添加、删除角色的时候使用SPRoleCollection中的方法。
- Add(string name, string description, SPRights permissionMask):添加一个角色,第一个参数指定角色的名称,第二个参数指定角色的描述,第三个参数指定角色所拥有的权限;
- Remove(int index):通过在集合中的下标删除该角色;
- Remove(string name):通过角色名称删除该角色;
- RemoveByID(int id):通过角色的id删除该角色。
SPRole的常用属性如下:
- Description:该角色的描述信息;
- ID:在该网站上唯一标识该角色的ID(int型)(只读);
- Name:该角色的名称;
- ParentWeb:该角色所在网站的对象(只读);
- PermissionMask:该角色所拥有的权限;
- Type:该角色的类型(仅对特殊角色有效)(只读);
- Users:该角色中的用户的集合;
- Xml:该角色的xml形式的描述(只读)。
在修改角色的信息后,需要调用SPRole.Update方法使修改生效。
在管理一个角色中的用户的时候,直接使用SPRole的方法(而不是在SPRole.Users属性中进行添加或删除)。
- AddUser(SPUser user):直接通过该用户的SPUser的对象实例来添加该用户;
- AddUser(string loginName, string email, string name, string notes):通过用户的基本信息添加该用户;
- RemoveUser(SPUser user):删除该用户。
【示例9-11】 获取网站中的角色,在不存在当前用户的角色中加入当前用户,然后遍历该角色中的所有用户。
// 首先获取到SPWeb对象web SPUser current = web.CurrentUser; foreach(SPRole role in web.Roles) { Console.WriteLine("Role:{0}", role.Name); if(role.Type != SPRoleType.Guest) try { SPUser user = role.Users[current.LoginName]; } catch { role.AddUser(current); } foreach(SPUser user in role.Users) Console.WriteLine("\tUser:{0}", user.Name); }
在该示例中,在添加用户的时候排除掉了“来宾”这一角色,这是因为该角色一般只应用在SPS的网站当中,无法将WSS网站中的普通用户加入该角色当中。
SharePoint的文件系统同样分为文件和文件夹这两大组成部分,但是与普通的asp.net编程不同的是,SharePoint中的文件和文件夹绝大部分是保存在数据库中的,只有一少部分(“_layouts”目录下的文件)是直接保存在服务器的文件系统中(这些文件默认的路径为:“C:\Program Files\Common Files\Microsoft Shared\web server extensions\60\TEMPLATE\ LAYOUTS”)。在一般的程序编写中,极少有需要去访问“_layouts”目录下的文件,而访问其他的文件(包括网页、文档库、图片库等)都需要通过SharePoint的对象模型来完成。本节主要介绍SharePoint文件相关的对象模型SPFolder和SPFile,之后会介绍列表中附件的对象模型SPAttachmentCollection,最后用一定的篇幅对SharePoint中特殊的列表“文档库”进行一些简要地说明。
SPFolder的使用
SPFolder是SharePoint对象模型中文件夹相关的类,它的使用方法相对比较简单。获取一个SPFolder的对象可以通过SPFolderCollection使用以下两种方法获得。
- folders[int index]:通过文件夹集合中的下标来获得;
- folders[string url]:通过该文件夹的url来获得。
而SPFolderCollection对象一般可通过SPWeb.Folders属性或SPFolder.SubFolders属性来获得。
而在SPWeb和SPList的对象模型中,都有该网站(或列表)所在的根目录的信息,可以直接通过SPWeb.RootFolder属性和SPList.RootFolder属性得到。但是需要特别指出的是,SPList.RootFolder的访问默认是没有开启的,如果想通过这种方法得到一个SPFolder对象,必须先将SPListCollection.IncludeRootFolder属性设为true。
在SPWeb中,也可以使用GetFolder方法来获得该网站中的某个文件夹对应的SPFolder对象。
- GetFolder(string url):参数为该文件夹所对应的路径(注意不要包含最后的“/”字符)。
- 文件夹的添加和删除同样是通过SPFolderCollection来完成的。
- Add(string url):添加一个文件夹,参数为待添加文件夹的url,该函数成功后直接返回一个SPFolder对象;
- Delete(string url):删除一个文件夹,参数为待删除文件夹的url。
- 在SPFolder类中,有如下一些常用的属性。
- ContainingDocumentLibrary:如果该文件夹是包含于一个文档库中的,那么该属性返回标识该文档库列表的Guid。该属性只读;
- Exists:判断该文件夹是否存在,在获取一个文件夹之后(尤其是通过url的方式获取一个文件夹之后),非常有必要先判断该文件夹是否存在,因为在获取文件夹的时候,文件夹不存在并不会引发异常,而在使用一个不存在的文件夹的时候,必然会引发异常。该属性只读;
- Files:该文件夹下的所有文件的集合;
- Name:该文件夹的名称(只读);
- ParentFolder:它的上一级文件夹的对象(只读);
- ParentWeb:该文件夹所在网站的对象(只读);
- ServerRelativeUrl:该文件夹相对于服务器根地址的url(只读);
- SubFolders:该文件夹下所有子文件夹的集合;
- Url:该文件夹相对于其所在网站的url(只读)。
SPFolder也提供了两个非常有用的函数。
- CopyTo(string newUrl):将该文件夹复制到参数所指定的url中;
- MoveTo(string newUrl):将该文件夹移动到参数所指定的url中。
【示例9-7】 一个简单的函数,通过递归的方法遍历某文件夹下的层级结构:
void LookupFolders(SPFolder parentFolder, int level) { for(int i=0; i<level; i++) Console.Write('\t'); Console.WriteLine(parentFolder.Name); foreach(SPFolder subFolder in parentFolder.SubFolders) { if(subFolder.Exists) LookupFolders(subFolder, level+1); } }
SPFile的使用
SPFile对应于SharePoint对象模型中的文件,它的使用方法与SPFolder类大致相似。在获取SPFile对象的时候,仍是通过SPFileCollection来进行,形式也与获取SPFolder相同。在SPWeb中,也同样提供了SPWeb.GetFile方法来获取一个文件。
- GetFile(string url):参数为该文件所在的url。
- 此外,对于文档库列表中的列表条目来说,也可以通过SPListItem.File来得到该文件的对象(关于文档库,稍候会进一步加以说明)。
- 在删除文件的时候,同样使用SPFile.Delete方法。
- Delete(string url):参数为待删除文件的url。
- 添加一个文件与添加文件夹稍有不同,需要指定文件的内容,并且有如下三种不同的形式。
- Add(string url, byte[] content):第一个参数指定待添加文件的url,第二个参数中以字节流的方式指定文件的内容。在指定文件url的时候,既可以使用完整的url(需要保证该目录存在),也可以只使用文件名(即添加到当前文件夹中)。使用该方法添加文件的时候,如果该url已经存在一个文件,则该函数会引发一个异常;
- Add(string url, byte[] content, bool overwrite):与上一种形式不同,这种形式通过第三个参数来指定当文件已存在时,是否进行覆盖。当overwrite为true时,会对重名的文件进行覆盖;否则,如果出现重名的情况,仍然会引发一个异常;
- Add(string url, byte[] content, SPUser createdBy, SPUser lastModifiedBy, DateTime timeCreated, DateTime timeLastModified):添加文件的时候,根据后4个参数,指定文件的创建者、修改者、创建时间、修改时间。但是在使用这种形式的时候需要注意,该程序的执行者必须为网站的管理员,而且该形式只有在WSS网站上有效(在SPS网站上,该方法会产生一个“Access Denied”错误)。
以上三种方法在创建成功之后均会直接返回一个SPFile类型的对象。
SPFile类中一些属性及其含义如下,这些属性一律为只读的。
- Author:文件的创建者,是一个SPUser类的对象(关于该类,会在下一节中进行说明);
- CheckedOutBy:文档库的文件允许进行签入和签出的操作,该属性为签出的用户;
- CheckedOutDate:文件签出的时间;
- CheckedInComment:文件签入时的评论内容;
- CheckOutExpires:文件签出的过期时间;
- CheckOutStatus:文件签出的状态,
- Exists:该文件是否存在;
- IconUrl:SharePoint为每种常用类型的文件都提供了图标,该属性中保存了该图标的图像文件的文件名(并非完整的url),这些图片一般保存在“_layouts/images/”目录下;
- InDocumentLibrary:表示该文件是否在文档库中;
- Item:如果该文件在文档库中,那么该属性(SPListItem类)获取该文件在该文档库列表中的列表条目对象;
- Length:文件的大小(以字节为单位);
- ModifiedBy:该文件的最后修改者;
- Name:该文件的文件名;
- ParentFolder:该文件所在的目录对象;
- Properties:一个Hashtable型的对象,包括该文件的一些常用属性(例如创建者、创建时间、修改者、修改时间、文件大小、文件的版本等信息);
- ServerRelativeUrl:该文件相对于服务器根地址的url;
- TimeCreated:文件创建的时间;
- TimeLastModified:文件最后修改的时间;
- Url:该文件相对于其所在网站的地址;
- Versions:SPFileVersionCollection类的对象,SharePoint的文档库可以支持文档的版本管理和控制,该属性中保存了该文件自创建以来的各个版本,同时保存了各版本的信息。(由于篇幅所限,不再一一列举SPFileVersion类的属性,有兴趣的读者请参考SDK。)
SPFile类中也同样提供了一些方法。
- CheckIn():将文件签入文档库;
- CheckOut():将文件从文档库中签出;
- CopyTo(string newUrl):将文件复制到一个新的url地址中;
- CopyTo(string newUrl, bool overwrite):将文件复制到新的url地址中,并指定是否覆盖同名文件;
- MoveTo(string newUrl):将文件移动到一个新的地址中;
- MoveTo(string newUrl, bool overwrite):将文件移动到一个新的地址中,并指定是否覆盖同名文件;
- OpenBinary():以byte[]的形式返回该文件的内容;
- SaveBinary(byte[] content):以参数为内容,保存该文件。
【示例9-8】 该示例中演示了从本地上传文件到文档库的过程:
// 首先获取到SPWeb对象web SPFolder folder = web.GetFolder("Shared Documents"); if(folder.Exists) { FileStream fs = new FileStream(@"C:\Demo.txt", FileMode.Open); byte[] content = new byte[fs.Length]; fs.Read(content, 0, (int)fs.Length); folder.Files.Add("Demo.txt", content); fs.Close(); } else{ Console.WriteLine("Folder Not Exist!"); }
该程序中的FileStream类和FileMode枚举是在System.IO命名空间中。