Sharepoint 2007 用代码聚合所有子网站文章 (populating data sources in code)

原文:http://sharepointmagazine.net/technical/development/populating-data-sources-in-code

按我们说,你想从一个网站集中的任何子网站中聚集新闻文章。现在,通过用作为AggregateDataSource链接数据源和SharePoint Designer这将是很容易做到这一点。但是一旦子网站变化,你将不得不在SPD里重新标记数据源或是纯手动地。

 

现在,有人会说,你可以使用跨站点SPDataSource做到这一点,等等,他们当然是对的。有得到的最终结果更简单的方法,但本文的目的是为了向你展示如何修改组件运行时。如果你想作一个简单的聚集,使用内容查询Web部件,一个跨站点SPDataSource甚至RSS。如果你想学习组件运行时修改,继续住下阅读。

 

只为了确保你理解我们的立场,我将解释AggregateDataSource以及在SPD如何创建一个链接的数据源。即使您知道如何做到这一点,请按照示例以便您了解我们面临的问题时,我们有一个动态的网站结构和的理解我们正在努力地聚集的网站结构。

 

首先,我们首先假设下面的网站结构:

现在,在每一个子网站中,我们有个自定义列表名为“文章”包含至少'Title'和'Pri'列表栏。我们需要有一个Web部件聚集所有的文章的所有标题,基于"pri"字段排序。

如果网站结构是静态的,你可以通过使用一种称为链接数据源来完成。启动SPD来创建一个,转到数据源库窗格。在最底部,点击“链接到其他库…”,然后,对于结构中每个子网站,单击添加,然后输入一个名称和子网站的位置。

 

 

如果你再看看数据源库,你会发现其中提供给你的数据源,你现在可以使用所有你输入的地址的子网站的列表。你可以添加任何一个Web部件列表或数据源到页面。但是,我们希望从数个列表里聚集所有文章,为此,我们需要一个链接数据源。

 

展开链接源节点,然后单击“新建链接源...”,然后按[配置链接源...]。对于之前添加的每个子网站,双击添加文章列表到‘选择的数据源’列表框,然后单击[下一步]。

 

 

在接下来的页面上,请确保您选择'合并'选项,然后单击完成。 如果你喜欢,请在常规选项卡,并添加一个名称,描述和此数据源的关键字。 完成后,单击确定。


一旦你创建了新数据源,你就能拖拽新数据源到一个页面来创建一个合并后的文章的DataFormWebPart (DFWP)。你可以操作该DFWP就像你操作任何一个其他列表据源DFWP。设置格式,添加或删除字段,应用布局排版,做你想做的。

 

 

这在已预定义或列表很少变化的的静态网站结构中很有效。但是,如果您选择添加,编辑或移除子网站包含你想要的信息汇总,你需要修改你的数据源。

 

现在,如果你观察在SharePoint Designer在代码视图的Web部件,其实你将看到你所添加的实际为一个普通的DataFormWebPart 包含一个DataSourece子节点,绿色的标记,包括一个AggregateDataSource。这些标记,只是.Net 类里展现为标签内容的很普通的标签。我们可以很容易操纵标签的内容,因而,使用自定义代码的类的行为。这就是我们如何能创建一个动态的AggregateDataSource。

 

第一件事首先,我们需要一个将操纵DataFormWebPart的数据源。创建一个新的ASPX页面,给它个名字(我的叫MyTestPage.aspx),然后拖拽你新创建的链接源在SPD设计视图中。如上所述任意布局排版或做其他任何。

现在,你可能会问:如果我要编写代码来操作数据源,为什么不直接写代码来创建整个DataFormWebPart? 很棒的问题,我很高兴你这样问。

 

简短的回答是:这样比较简易。

 

详细的回答是:嗯,如果你这样做,你要么需要继承或具有创建自定义的DataFormWebPart的能力。通过使用已经存在DFWP你可以格式化,排版和操作,使用内置的设计功能,唯一考虑的是显示什么数据,而不是怎么样。 设计者会爱上你这点;他们现在能极兴奋(go babanas)地漂亮做事,而你可以拖你自定义的组件到页面某处然更改要显示的数据。良好的开发实践使表现从数据中分离出来。

 

让我们继续我们的代码怎么样

 

从创建一个简单的自定义组件开始。如果你之前未曾做过,我已经写了一篇文章将引导你分步地创建自定义组件,位于http://furuknap.blogspot.com/2008/05/creating-your-own-custom-components-for.html。然而,这个例子中,不重写RenderContents方法,而是于OnLoad方法。如果你不希望写所有的代码,我附带了一个Visual Studio 2005

的解决方案“Begin”,可以在文章的未尾看到。现在就去,然后回来。我会在这里等你。

 

重载OnLoad,确保当我们加载该组件时可以访问DFWP的数据源。OnLoad事件发生在DataBinding事件之前,因此,我们确保在OnLoad中改变数据源是正确的设置数据源的时间。这一点很重要,一旦数据绑定方法已经执行就再没有办法去操纵他们,一直到结果显示出来。

 

33 protected override void OnLoad(EventArgs e)
34 {

 

既然我们要操作一个现有的DataFormWebPart控件, 我们需要一些方法去识别和访问这个控件。我们还需要一些途径知道哪些列表需要聚集。让我们解决这些问题通过添加一些属性到这个控件,添加以下行到你的类:

 

代码
17 private string m_DataFormWebPartId;
18
19  public string DataFormWebPartId
20 {
21 get { return m_DataFormWebPartId; }
22 set { m_DataFormWebPartId = value; }
23 }
24
25 private string m_ListName;
26
27 public string ListName
28 {
29 get { return m_ListName; }
30 set { m_ListName = value; }
31 }

 

这样做可以让我们在设计的时候配置这个组件。公有属性被用作asp.net 标签的一部分,对于实例:<MyTags:DynamicAggregateDataSource DataFormWebPartId =”MyDFWPId” ListName =”Articles” runat=”server”/>

 

现在我们有一个标识DFWP和聚集的列表名称,需要获得访问DFWP数据源的方式。然后我们可以开始操纵数据源。添加以下代码到OnLoad方法:

 

35 DataFormWebPart m_dfwp = this.Page.FindControl(DataFormWebPartId) as DataFormWebPart;
36
37 m_dfwp.DataSources.Clear(); // Empty datasources
38  
39 AggregateDataSource ads = new AggregateDataSource();
40  int sourceCounter = 0;
41 SPWeb web = SPContext.Current.Web;
42 StringBuilder aggregateString = new StringBuilder();
43
44 aggregateString.AppendLine("<concat name=\"data source\">");  

 

第35行我们获得了DFWP的引用。第37行清除当前数据源。第39-44行创建我们需要创建的数据源的对象和变量。我将稍候解释这些。

 

回去看DFWP标记,特别是DataSources标签:

 

代码
1 <DataSources>
2 <SharePoint:AggregateDataSource runat="server" IsSynchronous="false" id="Articles_x0020_from_x0020_all_x0020_subsites1″>
3 <sources>
4 <SharePoint:SPDataSource runat="server" DataSourceMode="List" UseInternalName="true" selectcommand="<View></View>">
5 <SelectParameters>
6 <asp:Parameter Name="ListID" DefaultValue="DD7603E8-1705-4AC4-8F9F-6BD31D6976ED"/>
7 </SelectParameters>
8 <DeleteParameters>
9 <asp:Parameter Name="ListID" DefaultValue="DD7603E8-1705-4AC4-8F9F-6BD31D6976ED"/>
10 </DeleteParameters>
11 <UpdateParameters>
12 <asp:Parameter Name="ListID" DefaultValue="DD7603E8-1705-4AC4-8F9F-6BD31D6976ED"/>
13 </UpdateParameters>
14 <InsertParameters>
15 <asp:Parameter Name="ListID" DefaultValue="DD7603E8-1705-4AC4-8F9F-6BD31D6976ED"/>
16 </InsertParameters>
17 </SharePoint:SPDataSource>
18 <SharePoint:SPDataSource runat="server" DataSourceMode="List" UseInternalName="true" selectcommand="<View></View>">
19 <SelectParameters>
20 <asp:Parameter Name="ListID" DefaultValue="9189EF30-7877-4B8D-9583-E7EE3C74C84F"/>
21 <asp:Parameter Name="WebURL" DefaultValue="/ss1/"/>

 

 

等等……为节约版面余下代码被省略

 

此标记指示数据源的作用和我们在代码里需要怎样去创建。首先,如第三行标记,需一个前段代码39行创建的AggregateDataSource。这之中包含一个属性,在第4行标记中,名称Source。Source属性,尽管我们只从标识中不能得知实际为什么类型,个税包含了许多SPDataSources的集合,标记行5和行19,其中又包含了一组Select、Delete、Update和Insert参数每个对象

 

代码
110 <aggregate>
111 <concat name=”data source”>
112 <datasource name=”Articles” id=”0″ Type=”SPList”/>
113 <datasource name=”Articles2″ id=”1″ Type=”SPList”/>
114 <datasource name=”Articles3″ id=”2″ Type=”SPList”/>
115 <datasource name=”Articles4″ id=”3″ Type=”SPList”/>
116 <datasource name=”Articles5″ id=”4″ Type=”SPList”/>
117 <datasource name=”Articles6″ id=”5″ Type=”SPList”/>
118 </concat>
119 </aggregate>
120  </SharePoint:AggregateDataSource>

 

 

 

此外,AggregateDataSource的Sources标签之后有一个aggregate标记包含了一些字串。

 

在AggregateDataSource类中,此属性不,尽管它呈现,一个集合,但而是一个字符串。这是明智的用aggregate属性作为一个集合,因此,我们就往里添加项目,但由于某些一些原因,情况并非如此。因此,我们需要为每个我们要添加的数据源使用唯一名字和id值创建这个字符串。这就是为什么我们在代码40和42行中有int型的sourcecounter和StringBuilder aggregateString。

 

所以我们可以开始考虑如何让我们的组件可以建立数据源。我们有了我们的AggregateDataSource,现在我们需要添加SPDataSources到Source属性中。

 

从我们要聚集许多子网站,使用一个递归函数是很有意义的,为其取名getSubWebItems。 现在,在我的实施中我会打破一些递归函数方面的最佳做法,但忍耐一下,我做的一个范例,您可能会希望实现自己的递归。

 

该函数的签名可以是这样的:

 

private void getSubWebItems(AggregateDataSource ads, ref int sourceCounter, StringBuilder aggregateString, SPWeb web)

 

 

 

该函数将使用Web和sourceCounter对象来操作的ads和aggregateString对象。让我们来看看:

 

代码
57 private void getSubWebItems(AggregateDataSource ads, ref int sourceCounter, StringBuilder aggregateString, SPWeb web)
58  58 {
59  try
60 {
61 SPList list = web.Lists[m_ListName];
62 SPDataSource sds = new SPDataSource();
63 Parameter p = new Parameter();
64 p.Name = "ListId";
65 p.DefaultValue = list.ID.ToString();
66 sds.SelectParameters.Add(p);
67
68 p = new Parameter();
69 p.Name = "WebURL";
70 p.DefaultValue = web.ServerRelativeUrl;
71 sds.SelectParameters.Add(p);
72
73 sds.DataSourceMode = SPDataSourceMode.List;
74 sds.UseInternalName = true;
75
76 sds.SelectCommand = "<View></View>";
77 ads.Sources.Add(sds);
78
79 aggregateString.AppendLine("<datasource name=\"" + m_ListName + sourceCounter + "\" id=\"" + sourceCounter + "\" Type=\"SPList\"/>");
80 sourceCounter++;
81
82 }
83  catch (Exception)
84 {
85 // Add your own error handling
86  }

 

 

一个好的开发人员总是会使用try - catch对吗?是的。行59和83-86所做的,是的,你需要添加错误处理。

 

行61取得一个我们当前已配置的SPWeb的组件中的ListName的引用。行62创建我们要添加到ads.DataSources的SPDataSource。然后,我们开始添加参数(行63-71),以及不同于标记代码所示,我们只添加select参数。你可能想或者需要添加其他insert, update 和delete更好,取决于你是否要DateFormWebpart可编辑。这样,就selectparameter模板。

 

在行77我们添加SPDateSource到ads.Sources属性之前我们完成SPDateSource的配置。

还记得看起来像是一个集合的奇怪的aggregate字符串吗?嗯,它只是一个字符串,我们需要拼起该字符串,使用sourceCounter让个数据源有个唯一的字符串。在69行之前,我们结束sourceCounter递增。

 

最后,我们需要通过调用相同的函数来递归内部本身。我们需要改变参数来确保不是一个无限循环。我们希望所有的子网站聚集好,所以我们在当前网站所有子网站中调用这个函数:

 

代码
88 try
89 {
90 foreach (SPWeb subweb in web.Webs)
91 {
92 getSubWebItems(ads, ref sourceCounter, aggregateString, subweb);
93 subweb.Dispose();
94 }
95
96 }
97 catch (Exception)
98 {
99 // Add your own error handling
100   }
101 }

 

 

代码的最后是在Onload方法里调用getSubWebItems,清除了一些东西,然后添加AggregateDataSource到DFWP控件。

 

46 getSubWebItems(ads, ref sourceCounter, aggregateString, web);
47
48 aggregateString.AppendLine("</concat>");
49
50 ads.Aggregate = aggregateString.ToString();
51
52 m_dfwp.DataSources.Add(ads);
53
54
55 }

 

 

第48-50行完成看起来像aggregateString的字符串,并将其添加到ads对象。

 

哇! 就是这样。 代码完成。 拍拍自己的背。 现在到了更容易的一部分,让它运行和工作用我们的DataFormWebPart。


现在是时间来部署我们的新组件,并添加到一个页面。这已被描述过多,包括我的位于http://furuknap.blogspot.com/2008/05/creating-your-own-custom-components-for.html的博客。我将会跳过这里,且调头回到SharePoint Designer把我们的组件进行测试。

在SPD,打开MyTestPage.aspx页然后添加Assembly和Register如我博客文章里描述的一样。在代码视图里将有智能感知。

 

通过查找之前添加的id-value完成自定义的ASP.net组件标记。并添加到你标记的DataFormWebPartId 字段里。也添加你要聚集的列表的ListName。当然还有runat="server":

 

<MyComponents:DynamicAggregateDataSource DataFormWebPartId=”g_0de093cc_8ba4_4c03_ba5a_b8b7591baf2a” ListName=”Articles” runat=”server”/>

 

保存,浏览器中打开,看看,你子站点的文章从此聚集到了一起。

 

 

回到美丽时刻……给出DataFormWebPart到你的designer。

让他们确保正如想要的一样。排序、过滤,做你想做的,你将拥有无需每次添加新站点时不断地更新链接源的动态数据源的所有权力。

 

要注意以下几点:

 

这不是可扩展的代码!这是高开销的操作,这个组件在每次进到这个页面的时候遍历你整个网站集。你很可能需要实施某种缓存或限制哪些页面可以使用这个组件。 关键是要展示你如何可以操纵数据源,不会给你生产代码。


记得添加你的程序集到到您的Web.config的SafeControls配置节点,参照:http://furuknap.blogspot.com/2008/05/creating-your-own-custom-components-for.html。如果不这样,将会出现未被允许的控件类型 "yourcomponent" 在这个页面。

 

当你更新或重新发布你的程序集记得重起IIS。另外,保留了你的组件签名的一份本地缓存,所此,如果你添加或修改属性,没有智能感知很可能是本地缓存干扰。要删除缓存,你需要转到【C:\Documents and Settings\[YourUserName]\Local Settings\Application Data\Microsoft\WebsiteCache】清空目录。别担心,你可以安全删除件夹中的每一项,它将被重建一旦你重新打开一个站点。清除缓存之前记得关闭SPD。

 

嘿,我们到了文章结尾。如果你有问题或者只想提出意见别忘了发表评论。我已上传了完整的Visual Studio解决方案以供您在什么问题的时候用。

 

方便您而附加的文件:

 

初始解决方案:

dynamicaggregatedatasource_begin1.zip

 

最终解决方案:

dynamicaggregatedatasource_end1.zip

posted @ 2010-11-21 09:02  客家岸田  阅读(647)  评论(0编辑  收藏  举报
联系和建议: antield[at]126.com