3.1 .NET客户端对象模型
.NET客户端对象模型是在SharePoint 2010引入的。在之前的版本,要想在客户端上和SharePoint通信,只能通过Web Service。Web Service使用起来并不方便,.NET客户端对象模型的推出,使程序员可以使用熟悉的对象模型来和SharePoint进行远程交互。
3.1.1 环境准备
使用.NET客户端模型的时候,Visual Studio可以在客户端机器上。本节会讲解如何在APS.NET网站里调用.NET客户端模型。在开始编码之前,需要在SharePoint和Visual Studio中做一些准备。
首先到SharePoint中,打开一个站点,创建一个通知列表,并且创建一些列表项,如图3-1所示。
图3-1 通知列表
然后准备Visual Studio环境。
.NET客户端对象模型的API文件存储在SharePoint服务器的C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI目录下,找到Microsoft.SharePoint.Client.Runtime.dll和Microsoft.SharePoint.Client.dll,拷贝到客户端机器上。
这里会以一个ASP.NET为宿主运行代码,读者也可以选择Windows窗体程序或者控制台程序。
打开Visual Studio,新建项目,选择“ASP.NET Web应用程序”,如图3-2所示。
图3-2 新建项目
在图3-3中选择空项目模板。
图3-3 选择空项目模板
这样一个空的项目就创建出来了。下一步是添加对SharePoint DLL的引用。在解决方案窗体里,右击“引用”,选择添加引用,在弹出的窗体里,选择“浏览”,并找到拷贝过来的两个SharePoint DLL文件,如图3-4所示。
图3-4 添加引用
引入之后,选中引入的文件,在属性窗体里,把“复制本地”改为True。这个选项能够确保在发布站点的时候,引入的dll文件能一起发布,如图3-5所示。
图3-5 复制本地属性
然后选中项目,右击,选择“添加”,在下一级菜单里选择Web窗体,命名为SharePointWeb。新建好之后,选中这个Web窗体,右击,选择设置为起始页,方便以后调试。
打开SharePointWeb.aspx.cs,加上对SharePoint客户端命名空间的引用:
using Microsoft.SharePoint.Client;
这样开发环境就准备完毕了。
3.1.2 ClientContext
在.NET客户端对象模型中,ClientContext是一切对象的入口,因此首先要初始化这个对象。ClientContext的初始化方法如下:
ClientContext context = new ClientContext("http://mysiteurl");
传给了ClientContext站点的URL还不够,就像在浏览器里登录SharePoint一样,还需要提供用户名密码。
context.Credentials = new NetworkCredential("username", "password", "domain");
然后就可以获取Site和Web对象了,从而进一步获取到List、ListItem。
.NET客户端对象模型和服务器端对象模型的结构是一样的,但是在命名上去掉了SP前缀,表3-1是对照表:
表3-1 .NET客户端对象模型和服务器端对象模型的比较
3.1.3 Site和Web对象
首先在SharePointWeb.apsx上面添加几个Label控件,用来显示站点信息:
<body> <form id="form1" runat="server"> <div> 网站标题:<asp:Label runat="server" id="webTitle" ></asp:Label><br/> 网站说明:<asp:Label runat="server" id="webDescription"></asp:Label><br/> </div> </form> </body>
1.获取Site和Web对象
获取Site的方法如下:
Site site = context.Site;
在客户端对象模型中,对网站集的操作是很弱的,基本上没有什么功能,这也是出于安全考虑。
获取网站集的顶层网站:
Web web = site.RootWeb;
和服务器端对象模型不同,获取Web对象不一定要先构造Site对象,可以通过ClientContext对象直接获取。
Web web = context.Web;
下面的代码演示如何获取Web的标题和说明,并显示在页面上。
在SharePointWeb.aspx.cs的Page_Load方法里面,添加如下代码:
protected void Page_Load(object sender, EventArgs e) { ClientContext context = new ClientContext("http://mysiteurl"); context.Credentials = new NetworkCredential("username", "pwd", "domain"); Web web = context.Web; context.Load(web); context.ExecuteQuery(); //只有执行ExecuteQuery才会和SharePoint通信 webTitle.Text = web.Title; webDescription.Text = web.Description; }
按F5键,运行结果如图3-6所示:
图3-6 查询站点信息的运行结果
使用.NET客户端对象模型,有以下几点需要注意:
● 通过ClientContext获取到的Site/Web对象,是不包含任何实际属性的,需要先调用Load,再调用ExecuteQuery方法,才会去和SharePoint通信,获取信息。
● Site和Web对象,不需要使用Using或者Dispose手动释放。
● 为了减少给服务器造成的压力,以及不必要的网络数据传输,应该尽量减少调用ExecuteQuery的次数,并且每次Load的时候只Load需要的信息。
在上面的例子里,Load了整个Web对象,但是实际上只使用了Title和Description两个属性,因此可以按照下面的代码优化,将context.Load(web)替换成:
context.Load(web, w => w.Title, w => w.Description);
上面的代码用到了Lambda表达式,因此要添加System.Linq的命名空间的引用。
2.更新站点属性
下面的代码演示如何更新Web对象的属性:
web.Title = "研发部门站点"; web.Description = "这个是研发部门站点,可以在这里分享文档和发起讨论和查看通知。"; web.Update(); context.ExecuteQuery();
这里需要注意的是,在更新SharePoint对象(调用Update方法)时,必须要调用context.ExecuteQuery();方法才会起作用。
再次把标题和说明显示在页面上,如图3-7所示:
图3-7 更新站点信息后的运行结果
3.建新站点
创建新的站点需要WebCreationInformation对象。这个也是和服务器端对象模型不一样的地方。下面的代码添加一个新的站点,并显示在页面上:
WebCreationInformation creation = new WebCreationInformation(); creation.Url = "serverteam"; creation.Title = "Server Team的站点"; creation.Description = "这个是研发部门下属Server小组的站点"; Web newWeb = web.Webs.Add(creation); context.Load(newWeb, w => w.Title, w => w.Description); context.ExecuteQuery(); webTitle.Text = newWeb.Title; webDescription.Text = newWeb.Description;
显示结果如图3-8所示:
图3-8 添加站点的运行结果
3.1.4 List对象
仿照前面的步骤,添加一个名为SharePointList.aspx的窗体,并在SharePointList.aspx.cs中的命名空间部分添加对Microsoft.SharePoint.Client和System.Linq的引用。在SharePointList.aspx中添加两个textbox:
<body> <form id="form1" runat="server"> <div> 列表集合:<br/> <asp:TextBox runat="server" id="allLists" TextMode="MultiLine" Height="300" Width="220" > </asp:TextBox><br/> 联系人列表栏:<br/> <asp:TextBox runat="server" id="contactListFields" TextMode="MultiLine" Height="300" Width="220" > </asp:TextBox><br/> </div> </form> </body>
1.获取列表信息
要获取到列表对象,同样需要先调用Load方法,在Load方法里面,指定需要获取的属性,比如标题,列表项个数,创建时间等,然后再调用context.ExecuteQuery();。
下面的代码演示如何通过Web对象获取站点里面的List的属性并显示在页面上。
Web web = context.Web; context.Load(web.Lists, lists => lists.Include(list => list.Title, list => list.ItemCount, list => list.Created)); context.ExecuteQuery(); foreach (List list in web.Lists) { allLists.Text +=list.Title + ":" + list.ItemCount+"\r\n"; }
运行结果如图3-9所示:
图3-9 列表标题和列表项个数
2.新建列表
创建新的列表需要借助于ListCreationInformation对象。
下面的代码演示如何新建一个联系人列表:
ListCreationInformation creationInfo = new ListCreationInformation(); creationInfo.Title = "联系人"; creationInfo.TemplateType = (int)ListTemplateType.Contacts; List newlist = web.Lists.Add(creationInfo); newlist.Description = "查看本部门的联系人信息"; newlist.Update(); context.ExecuteQuery();
同样,在调用完newlist.Update()之后,要调用context.ExecuteQuery()才能把新建请求提交给SharePoint。
在SharePoint里面,可以看到新建了一个联系人的列表,如图3-10所示。
图3-10 添加列表的运行结果
3.获取列表栏的信息
下面的代码演示如何获取列表里面所有的栏的名字和类型:
List contactlist = context.Web.Lists.GetByTitle("联系人"); context.Load(contactlist.Fields); context.ExecuteQuery(); foreach (Field field in contactlist.Fields) { contactListFields.Text += field.Title + ":" + field.TypeDisplayName + "\r\n"; }
结果如图3-11所示。
图3-11 列表的栏和类型
4.添加新栏
下面的代码演示如何给列表添加一个数字类型的栏,并且值的范围为15~100:
List contactlist = web.Lists.GetByTitle("联系人"); Field field = contactlist.Fields.AddFieldAsXml("<Field DisplayName='年龄' Type='Number' />", true, AddFieldOptions.DefaultValue); FieldNumber fldNumber = context.CastTo<FieldNumber>(field); fldNumber.MaximumValue = 100; fldNumber.MinimumValue = 15; fldNumber.Update(); context.ExecuteQuery();
这里用到了CastTo方法,将Field基类的对象,转换成具体的列表类型对象。
5.删除列表
代码如下:
List list = web.Lists.GetByTitle("MyListTitle"); list.DeleteObject(); context.ExecuteQuery();
3.1.5 Listitem对象
对列表项的常见操作也是增删改查。
1.查询列表项
查询列表项,要借助于CamlQuery对象来实现,下面的例子演示如何查询前100个列表项:
List contactlist = web.Lists.GetByTitle("联系人"); CamlQuery query = CamlQuery.CreateAllItemsQuery(100,new string[]{"Title","Email"}); Microsoft.SharePoint.Client.ListItemCollection items = list.GetItems(query); context.Load(items); context.ExecuteQuery(); foreach (Microsoft.SharePoint.Client.ListItem listItem in items) { allItems.Text += listItem["Title"] + "|" + listItem["Email"] + "\r\n" ; }
此段代码把前一百个联系人的姓和邮箱显示在页面上,结果如图3-12所示:
图3-12 显示列表项
在查询列表项的时候,有以下几点需要注意:
● 在CreateAllItemsQuery方法里定义返回条目数和栏(也可以使用CAML语言),以减少数据传输。
● 上面的代码包含了列表项和文件夹(Team A是一个文件夹),以及所有子文件夹里面的列表项的。如果只想查询特定的文件夹,需要给query.FolderServerRelativeUrl赋值。
● 可以使用CAML语言来定义查询的筛选条件,排序等。
2.新建列表项
新建一个列表项需要借助ListItemCreationInformation类。还是以上面的联系人列表为例:
ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation(); Microsoft.SharePoint.Client.ListItem newItem = list.AddItem(itemCreateInfo); newItem'"Title"' = "张"; newItem'"FirstName"' = "三"; newItem'"Email"' = "zhang.san@contoso.com"; newItem.Update(); context.ExecuteQuery();
这里要注意一点,栏的名字一定要用内部名称,而不是在页面上看到的名称。比如“姓氏”的内部名称是“Title”,而“名字”的内部名称是“FirstName”。
如何查看一个栏的内部名字呢?进入到列表设置页面,在栏的部分,选中一个栏,右键查看属性,末尾的属性就是内部名称,如图3-13所示:
图3-13 查看栏内部名称
3.更新列表项
代码如下:
listItem'"Company"' = "Contoso"; listItem'"JobTitle"' = "Manager"; listItem.Update(); context.ExecuteQuery();
4.删除列表项
代码如下:
listItem.DeleteObject(); context.ExecuteQuery();
5.新建文件夹
新建文件夹的过程和新建列表项的类似,但是要指定UnderlyingObjectType为Folder:
ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation(); itemCreateInfo.UnderlyingObjectType = FileSystemObjectType.Folder; Microsoft.SharePoint.Client.ListItem newItem = list.AddItem(itemCreateInfo); newItem["Title"] = "Team A"; newItem.Update(); context.ExecuteQuery();
3.1.6 使用.NET客户端对象模型的最佳实践
● 在做任何操作之后,一定要调用context.ExecuteQuery(),才能把修改提交到SharePoint端。
● 不能使用没有获取到的属性。
● 尽量减少和SharePoint交互的次数。
● 在请求SharePoint数据之前,限制查询的范围,比如只请求需要的属性或者列表项。