SharePoint 2013开发入门探索(二)- 列表操作

   我们如何用代码对SharePoint列表做些例如增删改查的操作呢?如果您的程序可以部署到服务器上,就可以使用 服务器对象模型,因为服务器对象模型提供的功能最多,限制最少;否则可能要选择客户对象模型等其他方式,这可能会遇到一些功能限制;另外还有一些其他的访问方式,例如Web服务等。如何在 SharePoint 2013 中选择正确的 API 集请参考链接 http://msdn.microsoft.com/zh-cn/library/jj164060.aspx。

     我们首先研究下服务器对象模型。使用服务器对象模型需要到服务器端部署,所以没有服务器部署权限的话就不能使用了。使用服务对象模型要引用程序集Microsoft.SharePoint —— 如果您创建的是SharePoint项目,这个引用默认就会有的。

       在服务器对象模型中我经常使用的几个.NET类是SPSite、SPWeb、SPList还有SPListItem,下面简单介绍下这几个类。

       网站集(由一个首要网站以及该网站下的所有网站组成,参考:http://technet.microsoft.com/zh-cn/library/cc262410.aspx)对应的类是SPSite,可以传参网站集URL给SPSite的构造方法创建对象。一般您可以这样用。

using (SPSite spSite = new SPSite("http://SharePointServer/"))
{//TODO......
}

      有时候你可能要提升一下权限以场管理员身份执行,则可以用下面的写法——这是服务器对象模型的优势,但是如果项目选择为“部署为沙盒解决方案”则不能提升到场管理员权限。

 

SPSecurity.RunWithElevatedPrivileges(() =>{using (SPSite spSite = new SPSite("http://SharePointServer/")){//TODO......}
});

 

      SharePoint里的用户对应的是SPUser类,也可以使用SPUserToken构造网站集对象实现模拟用户身份执行代码。

 

           SPSecurity.RunWithElevatedPrivileges(() =>{using (SPSite spSite = new SPSite("http://SharePointServer/")){SPUser imitatedUser = spSite.RootWeb.EnsureUser(@"contoso\sanzhang");SPUserToken token = imitatedUser.UserToken;using (SPSite siteWithUser = new SPSite("SharePointServerUrl", token)){//TODO......}}});

 

      网站对应的类是SPWeb,SPSite有一个RootWeb属性,是网站集的根网站;SPSite还有个AllWebs属性,是它的所有网站集合(可以用索引访问),要得到SPWeb对象还可以调用SPSite对象的OpenWeb方法,传给一个URL参数(根网站的URL和网站集是相同的,所以下面的代码传空字符串,其他子网站要传标识网站的URL部分)。每个SPWeb对象也有个Webs属性,是这个网站的子网站(也可以用索引访问)。

 

using (SPSite spSite = new SPSite("http://SharePointServer/"))
{//获取网站集根网站对象SPWeb spRootWeb = spSite.RootWeb;Console.WriteLine("网站集的根网站是{0}", spRootWeb.Title);//用网站ID获取子网站对象Guid webId = new Guid("{4a106421-ae78-40fd-ad62-77fecb67cf27}");SPWeb spWeb = spSite.AllWebs[webId];Console.WriteLine("该网站是{0}", spWeb.Title);spWeb = spRootWeb.Webs[webId];Console.WriteLine("该网站是{0}", spWeb.Title);//用网站名称获取子网站对象string name = "mysubweb1";spWeb = spSite.AllWebs[name];Console.WriteLine("该网站是{0}", spWeb.Title);spWeb = spRootWeb.Webs[name];Console.WriteLine("该网站是{0}", spWeb.Title);//用网站URL获取子网站对象string url = @"/mysubweb1";spWeb = spSite.OpenWeb(url);Console.WriteLine("该网站是{0}", spWeb.Title); 
}

 

     获取对网站和其他关键对象的引用请参考:http://msdn.microsoft.com/zh-cn/library/ms468609(v=office.14).aspx。

     列表对应的类是SPList,其实SPList类对应的不仅仅是狭义的自定义列表,文档库、图片库、日历、通知、任务都可以用它来操作,还有网站资产、用户信息列表、解决方案库、列表模版库、Web部件库等等。SPWeb对象有个Lists属性,是SPListCollection类型,遍历它或者用ID、Title做索引可得到SPList对象。想了解网站中有哪些List可以用下面的代码查看:

 

                    //获取网站所有列表foreach (SPList list in spWeb.Lists){Console.WriteLine("Title:{0} BaseType:{1} BaseTemplate:{2}", list.Title, list.BaseType, list.BaseTemplate);}//用列表标题获取列表对象string title = @"我的客户列表";SPList spList = spWeb.Lists[title];Console.WriteLine("该列表是{0}。", spList.Title);//用列表ID获取列表对象Guid id = new Guid(@"{3824b091-c7b8-409c-bcc0-7cce487d6b49}");spList = spWeb.Lists[id];Console.WriteLine("该列表是{0}。", spList.Title);//用列表URL获取列表对象string listUrl = string.Format(@"{0}/{1}", spWeb.Url, "Lists/MyCustomerList/AllItems.aspx");spList = spWeb.GetList(listUrl);Console.WriteLine("该列表是{0}。", spList.Title);

 

      您还是否记得这些列表属性,我们在开发自定义列表时都设置过?

      列表项对应的类是SPListItem,SPList对象的Items属性是它的项目的集合,是SPListItemCollection类型的,枚举它的元素就是SPListItem对象了。不过您想访问列表项的时候一般不要直接通过SPList对象的Items属性,特别是已经存储了很多项目的大数据列表,因为可能会有不必要的数据加载影响性能。例如您想知道列表中已存在多少个项目,可以直接访问SPList对象的ItemCount属性,而不是SPList对象的Items属性的Count;如果您想得到列表中的某个项目可以调用SPList对象的GetItemById、GetItemByUniqueId等方法。

 

                    //用列表标题获取列表对象SPList spList = spWeb.Lists["我的客户列表"];//获取用户信息列表的项目数量int userCount = spList.ItemCount;Console.WriteLine("我的客户列表共有{0}条项目。", userCount.ToString());//用项目ID获取项目对象int itemId = 18;SPListItem spListItem = spList.GetItemById(itemId);Console.WriteLine("该客户是{0}。", spListItem.Title);//用项目UniqueID获取项目对象Guid itemUniqueId = new Guid("{83815a27-6291-416d-8db6-a77bcae4bb86}");spListItem = spList.GetItemByUniqueId(itemUniqueId);Console.WriteLine("该客户是{0}。", spListItem.Title);

 

      列表对象还有一个Fields的属性,是SPFieldCollection类型,遍历这个字段集合可以得到SPField对象。这就是列表的字段信息,包括字段内部名称、显示名称、类型等等。我们要访问列表项目的某个属性时就可以用SPField对象的ID,InternalName或Title。

 

                    string title = @"我的客户列表";SPList spList = spWeb.Lists[title];SPFieldCollection spFields = spList.Fields;//获取列表的字段信息foreach (SPField field in spFields){Console.WriteLine("Title:{0}  InternalName:{1}  TypeDisplayName:{2}  TypeAsString:{3}", field.Title, field.InternalName, field.TypeDisplayName, field.TypeAsString);}Guid fieldId = new Guid("{a943ca8c-a2ad-4a90-8a78-2f6a202f6553}");SPField spField = spFields[fieldId];SPListItem spListItem = spList.Items[0];//用字段的ID访问列表项目属性Console.WriteLine("该用户的消费金额是{0}。", spListItem[spField.Id].ToString());//用字段的InternalName访问列表项目属性Console.WriteLine("该用户的消费金额是{0}。", spListItem[spField.InternalName].ToString());Console.WriteLine("该用户的消费金额是{0}。", spListItem.GetFormattedValue(spField.InternalName));//用字段的Title访问列表项目属性Console.WriteLine("该用户的消费金额是{0}。", spListItem[spField.Title].ToString());Console.WriteLine("该用户的消费金额是{0}。", spListItem.GetFormattedValue(spField.Title));

 

      您还记得开发自定义列表栏的时候我们一起设置的那些字段属性吗?

      SPList对象还有个GetItemByIdAllFields方法和GetItemByIdSelectedFields方法。看来我们可以按需索取项目字段了。

 

                   //用列表标题获取列表对象string title = @"我的客户列表";SPList spList = spWeb.Lists[title];int itemId = 1;SPListItem spListItem = spList.GetItemByIdSelectedFields(itemId, new[] { "CustomerName", "Recency", "Frequency", "Monetary" });//用项目的ID和字段的InternalName访问列表项目Console.WriteLine("客户{0}的最近消费时间是{1}消费频率是{2}消费金额是{3}。", spListItem["CustomerName"].ToString(), spListItem["Recency"].ToString(), spListItem["Frequency"].ToString(), spListItem["Monetary"].ToString());

 

      不过,我把GetItemByIdSelectedFields方法的数组参数减掉了两个项"Frequency"和"Monetary"再运行,竟然没有看到我期待的、闪电般美丽的异常!不是说只要两个字段吗?而且随后我把SPListItem对象的Xml属性也输出时有看到了好多不是我指定索取的字段信息!

 

                    string title = @"我的客户列表";SPList spList = spWeb.Lists[title];int itemId = 1;//删掉"Frequency"、 "Monetary"  SPListItem spListItem = spList.GetItemByIdSelectedFields(itemId, new[] { "CustomerName", "Recency"});//用项目的ID和字段的InternalName访问列表项目Console.WriteLine("客户{0}的最近消费时间是{1}消费频率是{2}消费金额是{3}。", spListItem["CustomerName"].ToString(), spListItem["Recency"].ToString(), spListItem["Frequency"].ToString(), spListItem["Monetary"].ToString());Console.WriteLine(@"XML:{0}",spListItem.Xml);

 

       查看一下GetItemByIdSelectedFields方法的源代码,发现在拼接CAML查询字段时有个对SPField对象MustFetchByDefault的判断,如果这个属性是True,没有指定也会查询,而且这个SPField对象MustFetchByDefault属性是internal的。

 

public SPListItem GetItemByIdSelectedFields(int id, params string[] fields)
{if (fields == null){throw new ArgumentNullException("fields");}StringBuilder builder = new StringBuilder();foreach (string str in fields){if (str != null){builder.Append("<FieldRef Name=\"" + str + "\"/>");}}foreach (SPField field in this.Fields){bool flag = false;foreach (string str2 in fields){if (str2 == field.InternalName){flag = true;break;}}if (!flag && field.MustFetchByDefault){builder.Append("<FieldRef Name=\"");builder.Append(field.InternalName);builder.Append("\"/>");}}return this.GetItemById(id, null, false, builder.ToString());
}

 

       如何读取列表项中字段的值请参考:http://msdn.microsoft.com/zh-cn/library/ff521580(v=office.14).aspx。

       在读取项目属性时,有些类型是比较特殊的:例如多个用户或用户组,它可以转为SPFieldUserValueCollection类型,这是个SPFieldUserValue对象的集合; 用户或用户组 、超链接或图片这样的字段取出来时String类型,您要解析可以用字符串截取方式,也可以对应构造成SPFieldUserValue、SPFieldUrlValue对象,直接访问它们的属性。

 

                    SPListItem spListItem = spList.GetItemById(itemId);//直接ToString,用户是[ID]+[;#] + [显示名];链接是[URL] + [,] + [显示文本]Console.WriteLine("客户的分享者是{0} 所有者是{1} 业务系统链接是{2}。", spListItem["Sharers"], spListItem["Owner"].ToString(), spListItem["BusinessPage"].ToString());//截取字符串取属性Console.WriteLine("客户的所有者的显示名是{0} 业务系统链接的URL是{1}。", spListItem["Owner"].ToString().Split(new[] { @";#" }, StringSplitOptions.None)[1], spListItem["BusinessPage"].ToString().Split(',')[0]);//转为相应对象取属性SPFieldUserValueCollection shares = (SPFieldUserValueCollection)spListItem["Sharers"];foreach (SPFieldUserValue share in shares){if (share.User != null){SPUser user = share.User;Console.WriteLine(@"找到个用户{0}", user.Name);}else{SPGroup spGroup = spWeb.Groups.GetByID(share.LookupId);Console.WriteLine(@"找到个用户组{0}", spGroup.Name);                       }}SPFieldUserValue owner = new SPFieldUserValue(spWeb, spListItem["Owner"].ToString());SPFieldUrlValue businessPage = new SPFieldUrlValue(spListItem["BusinessPage"].ToString());Console.WriteLine("客户的业务系统链接的URL是{0} 业务系统链接的描述是{1}。", businessPage.Url, businessPage.Description);

 

       如果您想按某些条件得到列表中的几个项目,则可以使用CAML列表查询了。上文中我们查看SPList的源代码,看到了一段XML的拼接,这就是CAML。协作应用程序标记语言 (CAML) 简介请参考:http://msdn.microsoft.com/zh-cn/library/ms426449.aspx。

       如果要直接使用CAML做查询可以使用SPList对象的GetItems方法,这个方法的参数是一个SPQuery对象。SPQuery对象的ViewFields是返回字段(个人理解ViewFieldsOnly要设置为True时ViewFields才有效,但是我尝试中发现不设置“ViewFieldsOnly=true”返回的结果是一样的。另外,ID、Created、Modified等属性一直会被返回的),Query是查询条件,这就相当于SQL语句里的"SELECT ..."和“WHERE...”了。GetItems方法的返回值是一个SPListItemCollection对象,如果喜欢用DataTable的话,可以调用它的GetDataTable()对象。举个简单的查询例子,查询名称为张三的客户:

 

                    SPList spList = spWeb.Lists[title];SPQuery spQuery = new SPQuery();spQuery.ViewFields = @"<FieldRef Name='CustomerName'/><FieldRef Name='Gender'/><FieldRef Name='Monetary'/><FieldRef Name='BusinessPage'/><FieldRef Name='Owner'/><FieldRef Name='Sharers'/>";//spQuery.ViewFieldsOnly = true;spQuery.Query = @"<Where><Eq><FieldRef Name='CustomerName'/><Value Type='Text'>张三</Value></Eq></Where>";SPListItemCollection spListItemCollection = spList.GetItems(spQuery);//将结果保存到DataTableDataTable dataTable = spListItemCollection.GetDataTable();Console.WriteLine(spQuery.ViewFieldsOnly.ToString());if (spListItemCollection.Count > 0){foreach (SPListItem spListItem in spListItemCollection){Console.WriteLine(spListItem["CustomerName"]);Console.WriteLine(spListItem.Xml);}}

复制代码

      CAML查询条件有很多比较符:Eq(=)、Gt(>)、Lt(<)、Geq(>=)、Leq(<=)、Neq(<>)、Contains(Like)、IsNull(Null)、IsNotNull(NotNull)等,多个查询条件可以使用关系运算符And或Or(http://msdn.microsoft.com/zh-cn/library/ms467521(v=office.14).aspx)。再举一个例子:自定义列表-我的客户列表有一个Sharers字段(表示分享用户列表),这个字段可存储多个用户和组,现在有一个用户甲,要查询分享给这个用户或这个用户所在的组的数据则使用如下代码:

复制代码

                    string title = @"我的客户列表";SPList spList = spWeb.Lists[title];SPUser user = spWeb.EnsureUser(loginName);SPGroup[] groups = user.Groups.Cast<SPGroup>().ToArray();SPQuery spQuery = new SPQuery();spQuery.ViewFields = @"<FieldRef Name='CustomerName'/><FieldRef Name='Gender'/><FieldRef Name='Monetary'/><FieldRef Name='BusinessPage'/><FieldRef Name='Owner'/><FieldRef Name='Sharers'/>";spQuery.ViewFieldsOnly = true;if (groups.Length > 0){StringBuilder query = new StringBuilder();query.AppendFormat(@"<Where><Or><Includes><FieldRef Name='Sharers' LookupId=""TRUE"" /><Value Type='User'>{0}</Value></Includes>", user.ID.ToString());Array.ForEach(groups, g => query.AppendFormat(@"<Includes><FieldRef Name='Sharers' LookupId='TRUE' /><Value Type='Group'>{0}</Value></Includes>", g.ID.ToString()));query.Append(@"</Or></Where>");spQuery.Query = query.ToString();}else{spQuery.Query = string.Format(@"<Where><Includes><FieldRef Name='Sharers' LookupId='TRUE' /><Value Type='User'>{0}</Value></Includes></Where>", user.ID.ToString());}DataTable dataTable = spList.GetItems(spQuery).GetDataTable();

复制代码

      SPQuery对象的ViewAttributes属性可以设置检索范围;RowLimit是返回数量ListItemCollectionPosition是查询位置,用这两个属性可以实现分页查询;列表中如果包含文件夹并且查询要在指定文件夹下执行,可以使用Folder属性。

       SPQuery类使用请参考http://technet.microsoft.com/zh-cn/library/microsoft.sharepoint.spquery.aspx ;如果您需要跨网站多列表混合查询,可以使用SPSiteDataQuery 类,http://msdn.microsoft.com/zh-cn/library/microsoft.sharepoint.spsitedataquery.aspx;查询列表项请参考http://msdn.microsoft.com/zh-cn/library/ms456030(v=office.14).aspx。如果您觉得拼写CAML有些麻烦,也可以到网站找一些小工具下载使用,例如:http://sharepointcamlhelper.codeplex.com/。关于查询性能,有几篇个人觉得不错的文章:http://msdn.microsoft.com/zh-cn/subscriptions/ee557257.aspx,http://www.infoq.com/cn/articles/SharePoint-Andreas-Grabner。

      新增列表项目可以先调用SPList对象的AddItem方法,获取一个新的SPListItem对象,在给SPListItem的所需字段赋值后再调用它的Update方法即可保存新增(SPListItem对象还有个SystemUpdate方法,这个方法在修改时不会影响修改时间和修改者,另外还可以用参数指定是否创建新版本)。

复制代码

                    SPUser user1 = spWeb.EnsureUser(loginName1);SPUser user2 = spWeb.EnsureUser(loginName2);SPGroup group1 = spWeb.Groups[loginName3];string title = @"我的客户列表";SPList spList = spWeb.Lists[title];SPListItem spListItem = spList.AddItem();spListItem["CustomerName"] = "赵六";spListItem["Gender"] = "女";spListItem["EMail"] = "liuzhao@contoso.com";spListItem["CellPhone"] = "13456435678";spListItem["WorkAddress"] = "西直门";spListItem["Recency"] = DateTime.Now;spListItem["Frequency"] = 0.5;spListItem["Monetary"] = 100000;spListItem["BusinessPage"] = new SPFieldUrlValue() { Url = "http://zhaoliu.com", Description = "赵六的个人主页" };spListItem["CustomerType"] = "钻石";spListItem["Owner"] = new SPFieldUserValue(spWeb, user1.ID, user1.Name);spListItem["Sharers"] = new SPFieldUserValueCollection { new SPFieldUserValue(spWeb, user1.ID, user1.Name),new SPFieldUserValue(spWeb, user2.ID, user2.Name), new SPFieldUserValue(spWeb, group1.ID, group1.Name) };spListItem.Update();

复制代码

      在给项目的字段赋值时,对于用户或用户组、超链接或图片这样的字段,也可以直接以字符串赋值。用户或用户组的ID和显示名要以“;#”连接,超链接或图片则以“,”连接URL和描述。

                    spListItem["BusinessPage"] = string.Format(@"{0},{1}", "http://sunqi.com", "孙七的个人主页"); spListItem["Owner"] = new SPFieldUserValue(spWeb, string.Format(@"{0};#{1}", user2.ID.ToString(), user2.Name));spListItem["Sharers"] = string.Join(@";#", user1.ID.ToString(), user1.Name, user2.ID.ToString(), user2.Name, group1.ID.ToString(), group1.Name); 

       如果项目有个附件文件如何上传呢?这个还很简单,只要使用SPListItem对象的Attachments属性就可以了。这是一个SPAttachmentCollection类型的SPAttachment集合,它有一个Add方法。

spListItem.Attachments.Add(Path.GetFileName(@"C:\1.txt"), File.ReadAllBytes(@"C:\1.txt"));

      上文我们提到,对文档库的操作也要使用SPList类,可是我看了一下SPListItem对象的File属性——它是只读的。 那么如何给文档库创建文件夹和上传文件呢?这次创建文件夹或文件的项目要用到SPList对象的AddItem重载方法,相关的SPFolder和SPFile也可以通过列表的网站SPWeb对象获取。

复制代码

                    string title = @"我的文档库";SPList spList = spWeb.Lists[title];//创建一个文件夹的SPListItem对象SPListItem folderListItem = spList.AddItem(spList.RootFolder.ServerRelativeUrl, SPFileSystemObjectType.Folder, "文件夹2");folderListItem.Update();//找到网站对应文件夹SPFolder对象SPFolder spFolder = spList.ParentWeb.GetFolder(folderListItem.UniqueId);bool allowUnsafeUpdates = spWeb.AllowUnsafeUpdates;//如果AllowUnsafeUpdates是False可能下面操作会有异常spWeb.AllowUnsafeUpdates = true;//在指定文件夹下添加文件spFolder.Files.Add(Path.GetFileName(@"C:\1.txt"), File.ReadAllBytes(@"C:\1.txt"));spWeb.AllowUnsafeUpdates = allowUnsafeUpdates;

复制代码

      再看看修改和删除列表项目就非常简单了。(参考资料:http://msdn.microsoft.com/zh-cn/library/ms467435(v=office.14).aspx)

复制代码

                    string title = @"我的客户列表";SPList spList = spWeb.Lists[title];//修改:int itemId = 5;SPListItem spListItem = spList.GetItemById(itemId);spListItem["CustomerName"] = "孙七七";spListItem.Update();//删除://spListItem.Delete();

复制代码

       不过要高效的批量执行增删改操作还是需要SPWeb对象的ProcessBatchData方法。命令语法请参考:http://msdn.microsoft.com/zh-CN/library/ms455433(v=office.12).aspx、http://msdn.microsoft.com/zh-cn/library/microsoft.sharepoint.spweb.processbatchdata.aspx、http://msdn.microsoft.com/zh-cn/library/cc404818.aspx。下面代码是插入、修改和删除的例子,对于多个用户和组、超链接或图片还是使用的字符串拼接(用户和组用“;#”连接ID和显示名称,超链接或图片用空格+逗号+空格连接URL和描述),还有时间类型字段,要转换为ISO8601格式,可以调用SPUtility类的CreateISO8601DateTimeFromSystemDateTime方法创建(http://msdn.microsoft.com/zh-cn/library/ms197282(v=office.14).aspx)。

复制代码

                    SPUser user1 = spWeb.EnsureUser(loginName1);SPUser user2 = spWeb.EnsureUser(loginName2);SPGroup group1 = spWeb.Groups[loginName3];string listId = @"3824b091-c7b8-409c-bcc0-7cce487d6b49";StringBuilder strBatchData = new StringBuilder(@"<?xml version=""1.0"" encoding=""UTF-8""?><Batch>");//命令头:string setListText = string.Format(@"<SetList Scope=""Request"">{0}</SetList>", listId);//插入数据:strBatchData.AppendFormat(@"<Method ID=""Insert,1"">{0}<SetVar Name=""ID"">New</SetVar><SetVar Name=""Cmd"">Save</SetVar>", setListText);strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "CustomerName", "蒋九");strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Gender", "男");strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "EMail", "jiujiang@contoso.com");strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "CellPhone", "13656435678");strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "WorkAddress", "菜市口");strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Recency", SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now.AddDays(-1)));strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Frequency", "0.3");strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Monetary", "30000");strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "BusinessPage", string.Format(@"{0} , {1}", "http://jiangjiu.com", "蒋九的个人主页"));strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "CustomerType", "青铜");strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Owner", string.Format(@"{0};#{1}", user2.ID.ToString(), user2.Name));strBatchData.AppendFormat(@"<SetVar Name=""urn:schemas-microsoft-com:office:office#{0}"">{1}</SetVar>", "Sharers", string.Join(@";#", user1.ID.ToString(), user1.Name, user2.ID.ToString(), user2.Name, group1.ID.ToString(), group1.Name));strBatchData.Append("</Method>");//修改数据:string updateItemId = "2";strBatchData.AppendFormat(@"<Method ID=""Update,1"">{0}<SetVar Name=""ID"">{1}</SetVar><SetVar Name=""Cmd"">Save</SetVar><SetVar Name=""urn:schemas-microsoft-com:office:office#{2}"">{3}</SetVar></Method>", setListText, updateItemId, "CustomerName", "李四四");//删除数据:string deleteItemId = "3";strBatchData.AppendFormat(@"<Method ID=""Delete,1"">{0}<SetVar Name=""ID"">{1}</SetVar><SetVar Name=""Cmd"">Delete</SetVar></Method>", setListText, deleteItemId);//命令尾:strBatchData.Append(@"</Batch>");//执行:Console.WriteLine(spWeb.ProcessBatchData(strBatchData.ToString()));

复制代码

      服务端对象模型还有一个很重要的上下文对象--SPContext,在开发Web部件时经常会用到。我们可以通过SPContext.Current获取到当前上下文SPContext对象,用该对象可以直接获取当前网站、当前列表、当前项目......(http://msdn.microsoft.com/zh-cn/library/microsoft.sharepoint.spcontext.aspx)

复制代码

            SPContext spContext = SPContext.Current;//当前网站集SPSite spSite = spContext.Site;//当前网站SPWeb spWeb = spContext.Web;//当前用户SPUser spUser = spWeb.CurrentUser;//当前列表SPList spList = spContext.List;//当前列表IDGuid listId = spContext.ListId;//当前项目SPItem spItem = spContext.Item;//当前项目IDint itemId = spContext.ItemId;//当前项目ID(字符串)string itemIdAsString = spContext.ItemIdAsString;//当前页面上下文SPContextPageInfo contextPageInfo = spContext.ContextPageInfo;//......

复制代码

 


      上文花了较大篇幅研究服务端对象模型,接下来我们研究托管客户端对象模型(托管客户端对象模型是用.NET开发的,另有ECMAScript客户端对象模型以后会介绍,http://msdn.microsoft.com/zh-cn/library/ee539429(v=office.14).aspx)。客户端对象模型不需要部署到服务器端,当然功能也会有一定限制。使用客户端对象模型代码需要引用Microsoft.SharePoint.Client程序集和Microsoft.SharePoint.Client命名空间。

      首先,我们要构建一个客户端上下文对象——ClientContext(相当于服务端对象模型的Microsoft.SharePoint.SPContext)。如果需要显式以某个用户的 Windows 凭据运行,可以给ClientContext对象的Credentials赋值。

复制代码

            ClientContext clientContext = new ClientContext(webFullUrl);//NetworkCredential networkCredential = CredentialCache.DefaultNetworkCredentials;//clientContext.Credentials = networkCredential;NetworkCredential networkCredential = new NetworkCredential(@"contoso\administrator", "password");clientContext.Credentials = networkCredential;

复制代码

       使用过了服务器端对象模型再理解客户端对象模型比较容易,与Microsoft.SharePoint.SPList对应的是Microsoft.SharePoint.Client.List、与Microsoft.SharePoint.SPListItem对应的是Microsoft.SharePoint.Client.ListItem,只是客户端对象模型要写更多代码,通过查询取得的对象不能直接使用,需要调用ClientContext对象的Load方法,并显式调用ExecuteQuery方法。(http://msdn.microsoft.com/zh-cn/library/ee534956(v=office.14).aspx、http://msdn.microsoft.com/zh-cn/library/gg277498.aspx)

复制代码

            string webFullUrl = "http://SharePointServer/";using (ClientContext clientContext = new ClientContext(webFullUrl)){           List list = clientContext.Web.Lists.GetByTitle("我的客户列表");CamlQuery camlQuery = new CamlQuery();//指定过滤条件camlQuery.ViewXml = @"<View><Query><Where><Eq><FieldRef Name='CustomerName'/><Value Type='Text'>蒋九</Value></Eq></Where></Query></View>";ListItemCollection listItems = list.GetItems(camlQuery);//加载查询,并指定加载字段:clientContext.Load(listItems,items => items.Include(item => item.Id,item => item["CustomerName"],item => item["Gender"],item => item["EMail"],item => item["CellPhone"],item => item["WorkAddress"],item => item["Recency"],item => item["Frequency"],item => item["Monetary"],item => item["BusinessPage"],item => item["CustomerType"],item => item["Owner"],item => item["Sharers"]));//执行查询clientContext.ExecuteQuery();int count = listItems.Count;foreach (ListItem item in listItems){Console.WriteLine("ID: {0} CustomerName: {1} Gender: {2}  EMail: {3} CellPhone: {4}  WorkAddress: {5}  Recency: {6}  Frequency: {7}  Monetary: {8} BusinessPage: {9} CustomerType: {10} Owner: {11} Sharers: {12} ",item.Id, item["CustomerName"], item["Gender"], item["EMail"], item["CellPhone"],item["WorkAddress"], item["Recency"], item["Frequency"], item["Monetary"],((FieldUrlValue)item["BusinessPage"]).Url, item["CustomerType"], ((FieldUserValue)item["Owner"]).LookupValue, string.Join(",", ((FieldUserValue[])item["Sharers"]).Select(v => v.LookupValue).ToArray()));}}

复制代码

      新增项目时也多了一个步骤,要先创建一个ListItemCreationInformation对象(添加附件还要创建AttachmentCreationInformation对象),再调用List的AddItem方法;为ListItem对象的属性赋值后,要调用Update和ExecuteQuery方法。

复制代码

            Guid listId = new Guid(@"{3824b091-c7b8-409c-bcc0-7cce487d6b49}");List list = clientContext.Web.Lists.GetById(listId);ListItemCreationInformation listItemCreationInformation = new ListItemCreationInformation();ListItem listItem = list.AddItem(listItemCreationInformation);listItem["CustomerName"] = "李四";listItem["Gender"] = "女";listItem["EMail"] = "sili@contoso.com";listItem["CellPhone"] = "13456435678";listItem["WorkAddress"] = "西直门";listItem["Recency"] = DateTime.Now;listItem["Frequency"] = 0.5;listItem["Monetary"] = 100000;listItem["BusinessPage"] = new FieldUrlValue() {  Url = "http://lisi.com", Description = "李四的个人主页" };listItem["CustomerType"] = "钻石";listItem["Owner"] = FieldUserValue.FromUser(loginName1);listItem["Sharers"] = new [] { FieldUserValue.FromUser(user1.LoginName),FieldUserValue.FromUser(user2.LoginName), FieldUserValue.FromUser(group1.LoginName)};listItem.Update();AttachmentCreationInformation attachmentCreationInformation = new AttachmentCreationInformation();using (FileStream fileStream = new FileStream(fileFullName, FileMode.Open)){attachmentCreationInformation.ContentStream = fileStream;attachmentCreationInformation.FileName = Path.GetFileName(fileFullName);listItem.AttachmentFiles.Add(attachmentCreationInformation);clientContext.ExecuteQuery();}

复制代码

      如果要上传一个文档到文档库则需要创建FileCreationInformation对象。

复制代码

                string title = @"我的文档库";List list = clientContext.Web.Lists.GetByTitle(title);Folder folder = list.RootFolder.Folders.Add("文件夹1");folder.Update();FileCreationInformation fileCreationInformation = new FileCreationInformation();fileCreationInformation.Content = System.IO.File.ReadAllBytes(fileFullName);fileCreationInformation.Overwrite = true;fileCreationInformation.Url = Path.GetFileName(fileFullName);folder.Files.Add(fileCreationInformation);clientContext.ExecuteQuery();

复制代码

      将项目修改或删除的代码很简单,也是操作后要调用ListItem对象的Update和ExecuteQuery方法。(http://msdn.microsoft.com/zh-cn/library/ee539976(v=office.14).aspx)

复制代码

                Guid listId = new Guid(@"{3824b091-c7b8-409c-bcc0-7cce487d6b49}");int itemId = 14;List list = clientContext.Web.Lists.GetById(listId);ListItem item = list.GetItemById(itemId);clientContext.Load(item);clientContext.ExecuteQuery();//修改item["CustomerName"] = "蒋九九";item.Update();clientContext.ExecuteQuery();//删除item.DeleteObject();clientContext.ExecuteQuery();

复制代码

 


      关于Web Services(http://msdn.microsoft.com/zh-cn/library/dd878586(v=office.12).aspx)的方式操作列表,首先要添加Web引用(解决方案资源管理器-〉引用-〉添加服务引用-〉高级(左下角)-〉添加Web引用(左下角)-〉URL输入框输入 http://<site>/_vti_bin/Lists.asmx.)。

      这里的操作命令语法和服务器端对象模型、客户端对象模型里的CAML非常相似,只是Web服务方法的参数和返回值多是XmlElement对象,查询列表项目shiyongLists.GetListItems 方法(请参考:http://msdn.microsoft.com/zh-cn/library/websvclists.lists.updatelistitems(v=office.12).aspx),下面是一个简单的查询例子。

复制代码

            string listName = "我的客户列表";using (Lists listService = new Lists()){listService.Credentials = CredentialCache.DefaultCredentials;//或者://listService.Credentials = new NetworkCredential(@"contoso\administrator", "password");XmlDocument xmlDocument = new XmlDocument();XmlNode queryNode = xmlDocument.CreateNode(XmlNodeType.Element, "Query", string.Empty);XmlNode viewFieldsNode =xmlDocument.CreateNode(XmlNodeType.Element, "ViewFields", string.Empty);viewFieldsNode.InnerXml = @"<FieldRef Name='ID' /><FieldRef Name='CustomerName' /><FieldRef Name='Gender' /><FieldRef Name='EMail' /><FieldRef Name='CellPhone' />";queryNode.InnerXml = string.Format(@"<Where><Eq><FieldRef Name='CustomerName'/><Value Type='Text'>{0}</Value></Eq></Where>", "蒋九");XmlNode resultNode = listService.GetListItems(listName, null, queryNode, viewFieldsNode, null, null, null);Console.WriteLine(resultNode.InnerXml);Console.ReadLine();}

复制代码

         新增、修改、删除列表项目使用Lists.UpdateListItems 方法执行批量命令(请参考:http://msdn.microsoft.com/zh-cn/library/websvclists.lists.updatelistitems(v=office.12).aspx)。对于多个用户和组、超链接或图片等特殊的字段类型还是使用的和服务器端对象模型相同的字符串拼接。

复制代码

            string listName = "我的客户列表";using (Lists listService = new Lists()){listService.Credentials = CredentialCache.DefaultCredentials;//或者://listService.Credentials = new NetworkCredential(@"contoso\administrator", "password");XmlDocument xmlDocument = new XmlDocument();XmlElement updatesBatch = xmlDocument.CreateElement("Batch");updatesBatch.SetAttribute("OnError", "Continue");StringBuilder methodsText = new StringBuilder();//删除数据:methodsText.AppendFormat(@"<Method ID='Delete,1' Cmd='Delete'><Field Name='ID'>{0}</Field></Method>", deleteItemId.ToString());//插入数据:methodsText.Append(@"<Method ID='Insert,1' Cmd='New'><Field Name='ID'>New</Field>");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "CustomerName", "蒋九");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Gender", "男");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "EMail", "jiujiang@contoso.com");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "CellPhone", "13656435678");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "WorkAddress", "菜市口");DateTime recency = DateTime.Now.AddDays(-1);methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Recency", string.Format("{0}-{1}-{2}T{3}:{4}:{5}Z", recency.Year.ToString("0000"), recency.Month.ToString("00"), recency.Day.ToString("00"), recency.Hour.ToString("00"), recency.Minute.ToString("00"), recency.Second.ToString("00")));methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Frequency", "0.4");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Monetary", "10000");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "BusinessPage", string.Format(@"{0} , {1}", "http://jiangjiu.com", "蒋九的个人主页"));methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "CustomerType", "青铜");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Owner", string.Format(@"{0};#{1}", user2.ID.ToString(), user2.Name));methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Sharers", string.Join(@";#", user1.ID.ToString(), user1.Name, user2.ID.ToString(), user2.Name, group1.ID.ToString(), group1.Name));methodsText.Append("</Method>");methodsText.Append(@"<Method ID='Insert,2' Cmd='New'><Field Name='ID'>New</Field>");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "CustomerName", "孙七");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Gender", "女");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "EMail", "qisun@contoso.com");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "CellPhone", "13656437456");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "WorkAddress", "恭王府");DateTime recency2 = DateTime.Now.AddDays(-3);methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Recency", string.Format("{0}-{1}-{2}T{3}:{4}:{5}Z", recency2.Year.ToString("0000"), recency2.Month.ToString("00"), recency2.Day.ToString("00"), recency2.Hour.ToString("00"), recency2.Minute.ToString("00"), recency2.Second.ToString("00")));methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Frequency", "0.6");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Monetary", "10000");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "BusinessPage", string.Format(@"{0} , {1}", "http://sunqi.com", "孙七的个人主页"));methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "CustomerType", "黄金");methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Owner", string.Format(@"{0};#{1}", user2.ID.ToString(), user2.Name));methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "Sharers", string.Join(@";#", user1.ID.ToString(), user1.Name, user2.ID.ToString(), user2.Name, group1.ID.ToString(), group1.Name));methodsText.Append("</Method>");//修改数据:methodsText.AppendFormat(@"<Method ID='Update,1' Cmd='Update'><Field Name='ID'>{0}</Field>", updateItemId.ToString());methodsText.AppendFormat(@"<Field Name='{0}'>{1}</Field>", "CustomerName", "赵六六");methodsText.Append("</Method>");updatesBatch.InnerXml = methodsText.ToString();XmlNode returnNode = listService.UpdateListItems(listName, updatesBatch);Console.WriteLine(returnNode.InnerXml);}

复制代码

 


     如果您觉得Web Services+XmlElement不够先进,还可以使用WCF+LINQ TO XML的方式,使用WCF直接添加服务引用就可以了。

      使用WCF访问SharePoint列表和使用Web Services访问的SharePoint的方法应该是同出一辙的,只是这里把参数XmlElement对象换成了XElement对象。可是开始的时候我还是遇到了一点小异常。

       对于这个MessageSecurityException类型的异常——“HTTP 请求未经客户端身份验证方案'Anonymous'授权。从服务器收到的身份验证标头为‘NTLM’。”,我们可以用添加两句代码,设置BasicHttpBinding.Security.Mode和BasicHttpBinding.Security.Transport.ClientCredentialType解决。

复制代码

                BasicHttpBinding basicHttpBinding = (BasicHttpBinding)listsSoapClient.Endpoint.Binding;basicHttpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;listsSoapClient.ClientCredentials.Windows.ClientCredential = new NetworkCredential(@"username", "password", "domain");XElement queryXElement = XElement.Parse(string.Format(@"<Query><Where><Eq><FieldRef Name='CustomerName'/><Value Type='Text'>{0}</Value></Eq></Where></Query>", "赵六六"));XElement viewFieldsXElement = XElement.Parse(@"<ViewFields><FieldRef Name='CustomerName'/><FieldRef Name='Gender'/><FieldRef Name='Monetary'/><FieldRef Name='BusinessPage'/><FieldRef Name='Owner'/><FieldRef Name='Sharers'/></ViewFields>");XElement resultXElement = listsSoapClient.GetListItems(listName, null, queryXElement, viewFieldsXElement, null, null, null);Console.WriteLine(resultXElement.ToString());

 

      如果您不喜欢加代码,还可以修改应用程序配置文件(.config)中的binding节点。 

 

  <system.serviceModel><bindings><basicHttpBinding><binding name="ListsSoap" ><security mode="TransportCredentialOnly"><transport clientCredentialType="Ntlm" /></security></binding></basicHttpBinding></bindings><client><endpoint address="http://SharePointServer/_vti_bin/Lists.asmx" binding="basicHttpBinding"bindingConfiguration="ListsSoap" contract="WebsvcLists.ListsSoap"name="ListsSoap" /></client></system.serviceModel>

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/439118.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CCNP-第二篇-SLA扩展+EIGRP高级版(上)

CCNP-第二篇-SLA扩展EIGRP高级版 还是这个环境的SLA 我们想一个问题哈,如果会有抖动呢? 比如左边是主线路,右边是备用的,那如果左边的时候只是偶尔断了一个包,然后他就跳到备用了,然后bfd检测到又跳回来了,这样如此循环,这个就叫做网络抖动,我们有啥办法让他不这样操作呢? …

SharePoint 2013开发入门探索(一)- 自定义列表

在SharePoint 2013中创建自定义列表的方式有很多&#xff0c;在网站内容页面添加应用程序就可以创建&#xff08;站点内容-〉 您的应用程序&#xff09;&#xff0c;也可以通过SharePoint Designer 2013创建&#xff0c;而本文将描述的是用Visual Studio 2012 创建自定义列表的…

使用C#代码部署SharePoint 2013开发包简单总结(一)

这篇文章将总结下如何将自己开发的列表、Web部件、事件接收器等元素部署到SharePoint的服务器。因水平有限&#xff0c;我的做法未必是最佳实践&#xff0c;会有些错误理解和疏漏&#xff0c;欢迎各位高手批评指正——但一定要能给出更好的方案。如果您是SharePoint开发的新手&…

CCNP-第三篇 EIGRP高级版(四个特性)(下)+OSPF复习

CCNP-第三篇 EIGRP高级版(四个特性)(下)OSPF复习 EIGRP篇到此完结 接下来四篇都是OSPF哦 EIGRP下发默认路由 来看一个环境 这种环境一般来说是很常见的,然后这个呢,下面的服务器,都是需要指向汇聚层的,那么如果环境很大的时候,每个机器都要手动写,就很麻烦了 >可以做一个…

CCNP-第四篇-OSPF高级版(一)

CCNP-第四篇-OSPF高级版(一) OSPFOpen shortes path first 开放式最短路径优先协议 最大优点:公有,开放,任何一个品牌都能用 EIGRP最大优点:快的一批 EIGRP最大缺点:思科私有 OSPF甚至于在Liunx上也能运行起来 OSPF是采用动态更新的 所以会给设备带来大量的硬件消耗 在OSPF中…

【转】DevOps到底是什么意思?

提到DevOps这个词&#xff0c;我相信很多人一定不会陌生。 作为一个热门的概念&#xff0c;DevOps近年来频频出现在各大技术社区和媒体的文章中&#xff0c;备受行业大咖的追捧&#xff0c;也吸引了很多吃瓜群众的围观。 那么&#xff0c;DevOps是什么呢&#xff1f; 有人说它…

CCNP-第五篇-OSPF高级版(二)

CCNP-第五篇-OSPF高级版(二) 链路状态数据库LSDB拓扑表 link state database 收到之后放入自己的数据库再计算最新的放入路由表 根据COST值来计算 >COST值的计算方式10的8次方除以带宽这个环境会涉及一个东西叫做重分布,这类会做,然后下一章或者下下章会详细开始讲. 详细环…

IIS 内部运行机制

ASP.NET是一个非常强大的构建Web应用的平台&#xff0c;它提供了极大的灵活性和能力以致于可以用它来构建所有类型的Web应用。 绝大多数的人只熟悉高层的框架如&#xff1a; WebForms 和 WebServices — 这些都在ASP.NET层次结构的最高层。 这篇文章的资料收集整理自各种微软公…

CCNP-第六篇-OSPF高级版(三)

CCNP-第六篇-OSPF高级版(三) 这一节差不多都是密码认证了,还有个NSSA和OE1,OE2 OSPF默认路由OSPF认证问题OSPF特殊区域,NSSA,STUB OSPF下发默认路由 其实跟EIGRP一样,只不过是下发一条路由给别人指向自己 一般都用于核心连接出口处,或者汇聚连接核心处 如果是这种环境下,那…

SharePoint 2013异常信息的查看

刚刚学习SharePoint开发的时候&#xff0c;经常遇到一些异常&#xff0c;却不能直接看到详细信息&#xff0c;很郁闷。这里做下简单的整理&#xff0c;方便查找&#xff1a; 1、代码未处理异常出现黄页——”‘/’应用程序中的服务器错误。运行时错误“。 其实这个黄页是ASP.N…

CCNP-第七篇-OSPF高级版(四)+策略开头

CCNP-第七篇-OSPF高级版(四)策略开头 今天讲NSSA和完全NSSA NSSA区域叫做非完全末节区域,这个东西都不知道命名的人怎么想的 因为完全NSSA区域叫做完全非完全末节区域,pleas,你人傻了吗? NSSA区域特点:过滤4,5类的LSA,同时会5类转为7类条目 7类在路由表里面是ON的 然后,7类除…

同步界面

设置FFS程序 当你下载、安装好后桌面会出现这两个图标。左边是主要的程序&#xff0c;右边软件用来设置自动同步。打开绿色图标的程序。 打开蓝色的设置按钮。 建议选择“文件时间和大小”。单纯的大小不能反映内容。比较文件内容又取决于硬盘速度。如果速度够快可以选择文件内…

CCNP-第八篇-分发列表+PRB+重分布+Route-Map

CCNP-第八篇-分发列表PRB重分布Route-Map 这个学不好,BGP就一定学不好 Route-Map 这样理解吧,在Route-map中 ACL就相当于警察,只能抓,不能判 Rroute-map呢就相当于法官,法官可以判罚 一般都是结合使用的,因为不结合这玩意也没法用环境如图 需求:干掉100.1.1.0/24 在Route-m…

虎年第一篇-CCNP-第九篇-BGP(一)

CCNP-第九篇-BGP(一) 首先,开工啦,祝大家2022新年快乐虎年大吉,虎虎生威哦BGP是一个网络工程师的分水岭 这是真的,BGP一般很大的企业才能用得上,或者ISP运营商 人家可以不用,但是你不能不会吧, BGP,CCIE必考 BGP有四节课基础,后面CCIE的部分还有 从BGP开始就要换一种理念 因为之…

rsync算法原理及使用

如果服务器之间需要保持某些文件的一致&#xff0c;我们可以使用scp来复制&#xff0c;如果需要长期保持一致&#xff0c;可以配合crontab脚本来使用。但是此时我们有更优的方式&#xff0c;就是rsynccrontab来实现定时增量传输保持文件一致。 rsync功能很强大&#xff0c;网上…

CCNP-第十篇-BGP(二)

CCNP-第十篇-BGP(二) 首先 BGP都基本上部署在PE,CE设备 PE:Provider edge 运营商边界 CE:Customer edge 用户边界 建立BGP 1.一般呢,是会使用环回口建立BGP 2.因为他是虚拟接口,很稳定,而且不会down,只要系统在,他就不会down;; 3.如果他down了就是整个网络都断了 4.节约接口使…

CCNP-第十一篇-BGP(三)(精髓篇)

CCNP-第十一篇-BGP(三) BGP十三条线路原则(大点) 能修改的前7条,後6条是无法修改的,所以实际上7条 跟ACL一样,从上往下执行,比如第一条比较出来了就不会继续往下了 工作中比较多用的,第四条根据as-path一,权重-Weight 1.思科里面叫权重,是思科私有的,在华为叫首选优先级(Pre…

WSS 数据库表中的 UserInfo 表中的 tp_SystemId 字段的使用

在 WSS 的数据库中&#xff0c;UserInfo表的 tp_SystemId 记录的是用户登录验证时需要用到的数据&#xff0c;是此用户在 AD( Active Directory ) 中的 SID( Security ID )。此字段的数据很重要&#xff0c;不小心改动的话&#xff0c;此用户将不能登录 WSS。 这里介绍一下如何…

CCNP-第十二篇-BGP(四)

CCNP-第十二篇-BGP(四) 这次接着上次的选路原则继续干 上次是前6条,现在是跟后面的7条 BGP的选路原则默认是11条,最大可以配置后去到13条七.EBGP路由优于IBGP 这个不知道咋讲呢 如果A-B-C 那么A-B为IBGP B-C为EBGP的话 他们同时宣告一个条目 在两边对称的情况下,会选择EBGP宣告…

使用Module自定义网站定义(Site Definition)

在WSS SDK中有一篇文章介绍了使用Modules添加文件到网站定义中(可以在http://msdn.microsoft.com中搜索Using Modules to Add Files to a Site Difinition找到)&#xff0c;不过很多东西只是稍微提了一下&#xff0c;具体怎么操作并没有讲到。 一般的&#xff0c;我们可以用下…