DNN搜索引擎研究续 • 如何使自定义模块加入DNN搜索引擎
提纲挈领地,要使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
21Imports DotNetNuke.Services.Search
22
23Namespace DotNetNuke.Entities.Modules
24 Public Interface ISearchable
25 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(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
原因是在搜索引擎运行时,会读取模块的此属性,然后使用反射创建Controller Class,检查它是否实现了ISearchable接口。(具体代码在Provider.Search.Index项目的ModuleIndexer类的GetModuleList方法中。)事实上,如果不填写Controller
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。)