提纲挈领地,要使DNN的自定义模块加入搜索引擎,有如下3个要点:
1、自定义模块的Controller类要实现ISearchable接口。这个是肯定的。
2、模块定义时一定要填写Controller Class属性。因为搜索引擎的调度执行的时候,会利用反射创建Controller Class,寻找实现ISearchable接口的GetSearchItem方法。
3、DNN_DesktopModules表的SupportedFeatures字段,要填3。
--------------------------------------------------------------------------------------------------------
1、先看如何实现ISearchable接口。
在先前的DNN搜索引擎研究中提到:在DNN的架构中,提供了一个ISearchable的接口,只要实现这个接口的模块,都可以作为搜索的数据源。同样的,你如果想让自己写的模块被搜索引擎收录的话,你就要实现ISearchable接口。
我们来看一下ISearchable接口的内容,该接口位于DotNetNuke/Components/Modules(在解决方案中的路径)下面。
2 ' DotNetNuke?- http://www.dotnetnuke.com
3 ' Copyright (c) 2002-2005
4 ' by Perpetual Motion Interactive Systems Inc. ( http://www.perpetualmotion.ca )
5 '
6 ' Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7 ' documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8 ' the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
9 ' to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10 '
11 ' The above copyright notice and this permission notice shall be included in all copies or substantial portions
12 ' of the Software.
13 '
14 ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
15 ' TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16 ' THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17 ' CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 ' DEALINGS IN THE SOFTWARE.
19 '
20
21 Imports DotNetNuke.Services.Search
22
23 Namespace DotNetNuke Namespace DotNetNuke.Entities.Modules
24 Public Interface ISearchableInterface ISearchable
25 Function GetSearchItems()Function GetSearchItems(ByVal ModInfo As ModuleInfo) As SearchItemInfoCollection
26 End Interface
27End Namespace
28
很简单,该接口只有一个方法声明,GetSearchItems,在搜索引擎执行的时候,DNN会根据此方法获取能够被搜索的模块项目。那么,如何实现该接口呢?我们首先看一下DNN自带的模块是怎么做的,比如Links模块。
2 ' '' <summary>
3 ' '' GetSearchItems implements the ISearchable Interface
4 ' '' </summary>
5 ' '' <remarks>
6 ' '' </remarks>
7 ' '' <param name="ModInfo">The ModuleInfo for the module to be Indexed</param>
8 ' '' <history>
9 ' '' [cnurse] 11/17/2004 documented
10 ' '' </history>
11 ' '' -----------------------------------------------------------------------------
12 Public Function GetSearchItems() Function GetSearchItems(ByVal ModInfo As Entities.Modules.ModuleInfo) As Services.Search.SearchItemInfoCollection Implements Entities.Modules.ISearchable.GetSearchItems
13 Dim SearchItemCollection As New SearchItemInfoCollection
14
15 Dim Links As ArrayList = GetLinks(ModInfo.ModuleID)
16
17 Dim objLink As Object
18 For Each objLink In Links
19 Dim SearchItem As SearchItemInfo
20 With CType(objLink, LinkInfo)
21 '
22 Dim UserId As Integer = Null.NullInteger
23 If IsNumeric(.CreatedByUser) Then
24 UserId = Integer.Parse(.CreatedByUser)
25 End If
26 SearchItem = New SearchItemInfo(ModInfo.ModuleTitle & " - " & .Title, .Description, UserId, .CreatedDate, ModInfo.ModuleID, .ItemId.ToString, .Description, "ItemId=" & .ItemId.ToString, Null.NullInteger)
27 SearchItemCollection.Add(SearchItem)
28 End With
29 Next
30
31 Return SearchItemCollection
32 End Function
33
参照这些代码,我们可以书写自己的GetSearchItems方法了。注意,这个接口的实现是写在模块的Controller类中的。假如你要写一个新闻模块,那么GetSearchItems方法可以书写如下:
2 {
3 DotNetNuke.Services.Search.SearchItemInfoCollection searchItems = new DotNetNuke.Services.Search.SearchItemInfoCollection();
4 ArrayList News = List(ModInfo.ModuleID);
5 foreach(NewsInfo news in News)
6 {
7 DotNetNuke.Services.Search.SearchItemInfo item;
8 item = new DotNetNuke.Services.Search.SearchItemInfo(ModInfo.ModuleTitle + "-" + news.Title,news.Content,Null.NullInteger,news.CreateDate,ModInfo.ModuleID,news.ItemID.ToString(),news.Content,Null.NullInteger);
9 searchItems.Add(item);
10 }
11 return searchItems;
12 }
13
2、在模块管理中进行模块定义时,一定要填写Controller Class属性。
原因是在搜索引擎运行时,会读取模块的此属性,然后使用反射创建Controller Class,检查它是否实现了ISearchable接口。(具体代码在Provider.Search.Index项目的ModuleIndexer类的GetModuleList方法中。)事实上,如果不填写Controller Class,模块也能正常使用,其他地方没有任何异常,所以我就习惯了不填它,结果费了很大劲才搞明白原来是这儿的原因。
3、DNN_DesktopModules表的SupportedFeatures字段,要填3。
这个就更诡异了。SupportedFeatures这个字段是什么意思呢?风云在DNN配置-数据库篇中有所解释,该字段表示模块支持的特性。DNN中有个DesktopModuleInfo类,对该属性有所描述:
2 IsPortable = 1
3 IsSearchable = 2
4 End Enum
ModuleInfo类中也有该属性,并且初始值为0。但在模块管理的Add、Update事件中,根本找不到是在哪儿对该属性赋值的,也就是说,你自定义的模块插入到数据库中,该字段的值肯定是0。
但是,DNN使用GetSearchModules存储过程获取能够搜索的模块,其中有个where条件是:(DesktopModules.SupportedFeatures & 2 = 2)。因此无论如何你的自定义模块是不会满足这个条件的。去看看Links、Text/Html这些DNN自带的能够搜索的模块,发现这个字段是3。那么3代表什么呢?不知道。把自己的模块也改成3,果然就行了。不知道这个是DNN留出的一个扩充接口呢,还是一个Bug。
(我使用的DNN版本是3.2.2。)