背景
我正在尝试创建一个C#命令行实用程序,以从特定网站集中任何位置可能存在的列表中提取列表项信息。我尝试从中提取的所有列表都是从ID为10003(自定义模板)的特定模板创建的。
这些权力仍在决定这个事情的运行频率,但是我希望每隔几分钟左右就能得到一个答案,所以我需要执行的时间不过是一个分钟,并且不要认为用我现在的方法可以实现。
我有一个网站集,其中包含7个直接子节点和大约200个后代子网站,这些列表可能出现在其中任何一个中。大多数实例只有几个项目,但其中一些将有几千个。我总共期待约10-20k的结果。
此实用程序将在远程服务器上运行,在内部我们更喜欢使用CSOM而不是休息。我熟悉SP Web部件开发,但这是我第一次需要使用CSOM。
The Farm是一个SP 2010 On Prem,有3个WFE,用最新的CU更新。
即时问题:
代码:
我目前的尝试是这样的:
using (var ctxt = new ClientContext(url))
{
var webs = ctxt.Web.Webs;
ctxt.Load(webs);
ctxt.ExecuteQuery();
var allItems = new List<ListItem>();
foreach (var web in webs)
{
ctxt.Load(web.Lists);
ctxt.ExecuteQuery();
foreach (var list in web.Lists)
{
if (list.BaseTemplate == 10003)
{
ctxt.Load(list);
ctxt.ExecuteQuery();
var items = list.GetItems(query);
ctxt.Load(items);
ctxt.ExecuteQuery(); // <- **throws "Cannot complete this action." on first iteration of loop.**
allItems.AddRange(items);
}
}
}
results = allItems.Select(ConvertToNeededResultType).ToList();
}
查询看起来像:
<View Scope='RecursiveAll'>
<Webs Scope='SiteCollection' /> <!--**If I omit this line, I get a CollectionNotInitialized exception on allitems.AddRange(items)**--/>
<Lists ServerTemplate='10003' />
<Query>
<OrderBy>
<FieldRef Name='CreatedOn' Ascending='False' />
</OrderBy>
<Where>
<And>
<Eq>
<FieldRef Name='FSObjType' />
<Value Type='Integer'>0</Value>
</Eq>
<Geq>
<FieldRef Name='CreatedOn'/>
<Value Type='DateTime' IncludeTimeValue='FALSE'>{0}</Value>
</Geq>
</And>
</Where>
<Query>
<ViewFields>
<FieldRef Name='Title' Nullable='TRUE' />
<FieldRef Name='URL' Nullable='TRUE' />
<FieldRef Name='CreatedOn' Nullable='TRUE' />
<FieldRef Name='Category' Nullable='TRUE' />
<FieldRef Name='Attachments' Nullable='TRUE' />
<FieldRef Name='ID' />
<ProjectProperty Name='Title' />
<ListProperty Name='Title' />
</ViewFields>
</View>
其中{0}包含的日期是我希望以格式返回列表的天数:&#34; yyyy-MM-ddTHH:mm:ssZ&#34;
我在寻找什么:
我正在寻找有关如何使用我当前的代码解决上面列举的特定问题的建议,或者提供有关如何更有效地实现相同结果的示例的建议。
答案 0 :(得分:0)
我从未弄清楚&#34;无法完成此操作&#34;但是我已经用另一种方式解决了这些要求:我需要两种方法,递归用于抓取网页和检索项目:
public static IEnumerable<WebLocation> GetWebLocations(string rootWebUrl)
{
List<WebLocation> results;
using (var cntxt = new ClientContext(rootWebUrl))
{
var web = cntxt.Web;
cntxt.Load(web, w => w.Webs, w => w.Id, w => w.ServerRelativeUrl, w => w.Lists);
cntxt.ExecuteQuery();
results = GetWebLocations(cntxt, web, Guid.Empty);
}
return results;
}
private static List<WebLocation> GetWebLocations(ClientContext cntxt, Web currentWeb, Guid parentId)
{
var results = new List<WebLocation>();
var currentId = currentWeb.Id;
var url = currentWeb.ServerRelativeUrl;
var location = new WebLocation { ParentSiteID = parentId, SiteID = currentId, WebUrl = url, HotLinksItems = new List<HotLinksItem>() };
foreach (var list in currentWeb.Lists)
{
cntxt.Load(list, l => l.BaseTemplate, l => l.RootFolder.ServerRelativeUrl);
cntxt.ExecuteQuery();
if (list.BaseTemplate == 10003)
{
var itemCollection =
list.GetItems(new CamlQuery
{
ViewXml = "<View Scope='RecursiveAll'><ViewFields><FieldRef Name='Title' Nullable='TRUE' /><FieldRef Name='ID' /><ProjectProperty Name='Title' /><ListProperty Name='Title' /></ViewFields></View>"
});
cntxt.Load(itemCollection);
cntxt.ExecuteQuery();
foreach (var item in itemCollection)
{
var hotlink = new HotLinksItem
{
Title = item["Title"] != null ? item["Title"].ToString() : null,
ID = item["ID"] != null ? item["ID"].ToString() : null,
};
location.HotLinksItems.Add(hotlink);
}
}
}
}
我仍然感觉自己做了太多的电话,但是通过子选项将它们削减,这有助于提高性能,总而言之,对我的农场来说,这个东西在30秒内运行。 (在减少退货项目之前,大约需要3分钟。)