ISearchableContentType 接口支持使内容可搜索。当搜索索引作业运行时,此插件将收集有关您的内容信息。
搜索是任何平台的强大功能。如果使您的内容可被发现,那么规划搜索策略非常重要。考虑哪些属性怎么索引非常重要,可以使您的内容在搜索页上与其他内容区分开来。
若要添加对搜索的支持,必须实现 ISearchableContentType。它是在 Limyee.Core.dll 的 Limyee.Extensibility.Content.Version1 命名空间中定义。
请务必注意,可以在同一 IContentType 类中实现一个或多个核心服务。
首先定义一种方法来标记哪些内容是搜索提供程序索引的,哪些内容不是索引的。
public void SetIndexStatus(Guid[] contentIds, bool isIndexed)
{
LinksData.UpdateStatus(contentIds, isIndexed);
}
对于下一个方法,重要的是要考虑将索引哪些字段。您需要使用 API 构建 SearchIndexDocuments 列表:Apis.Get<ISearchIndexing>().NewDocument()。
public IList<SearchIndexDocument> GetContentToIndex()
{
var docs = new List<SearchIndexDocument>();
var links = LinksData.ListLinks().Where(link => !link.IsIndexed);
foreach (var link in links)
{
if (link == null) { continue; }
var doc = Apis.Get<ISearchIndexing>().NewDocument(link.ContentId, link.ContentTypeId, "linkitem", link.Url, link.HtmlName("web"), link.HtmlDescription("web"));
doc.AddField("date", Apis.Get<ISearchIndexing>().FormatDate(link.CreatedDate));
docs.Add(doc);
}
return docs;
}
安全检测是搜索提供程序的另一个重要功能。它确定用户是否有权查看某些内容。这将要求您返回允许查看您的内容的角色列表。
public int[] GetViewSecurityRoles(Guid contentId)
{
var content = LinksData.GetLink(contentId);
if (content == null) { return new int[] { }; }
if (content.Application == null) { return new int[] { }; }
return Apis.Get<IRoles>().Find("Registered Users").Select(r => r.Id.GetValueOrDefault()).ToArray();
}
要实现的最后一个方法是返回搜索结果的 html 视图。返回一致的格式非常重要,但您可以完全控制为内容返回的标记。
public string GetViewHtml(IContent content, Target target)
{
if (content == null) { return null; }
var user = Apis.Get<IUsers>().Get(new UsersGetOptions { Id = content.CreatedByUserId });
var author = String.Format(@"<a href=""{0}"" class=""internal-link view-user-profile""><span></span>{1}</a>", Apis.Get<IHtml>().EncodeAttribute(user.ProfileUrl), Apis.Get<IHtml>().Encode(user.DisplayName));
var appLink = content.Application != null
? String.Format(@"<a href=""{0}"">{1}</a>", Apis.Get<IHtml>().EncodeAttribute(content.Application.Url), content.Application.HtmlName(target.ToString()))
: String.Empty;
var groupLink = content.Application != null && content.Application.Container != null
? String.Format(@"<a href=""{0}"">{1}</a>", Apis.Get<IHtml>().EncodeAttribute(content.Application.Container.Url), content.Application.Container.HtmlName(target.ToString()))
: String.Empty;
return String.Format(@"
<div class=""abbreviated-post-header""></div>
<div class=""abbreviated-post ui-searchresult"">
<div class=""post-metadata"">
<ul class=""property-list"">
<li class=""property-item date"">{0}</li>
<li class=""property-item author"">
<span class=""user-name"">{1}</span>
</li>
<li>
<ul class=""details"">
<li class=""property-item type""></li>
</ul>
</li>
</ul>
</div>
<h4 class=""post-name"">
<a class=""internal-link view-post"" title=""{3}"" href=""{4}"">
{2}
</a>
</h4>
<div class=""post-summary"">{5}</div>
<div class=""post-application"">
{6}
{7}
</div>
</div>
<div class=""abbreviated-post-footer""></div>",
Apis.Get<ILanguage>().FormatDate(content.CreatedDate),
author,
content.HtmlName("web"),
content.HtmlName("web"),
Apis.Get<IHtml>().EncodeAttribute(content.Url),
content.HtmlDescription("web"),
appLink,
groupLink);
}
下面是完整示例。
using System;
using System.Collections.Generic;
using System.Linq;
using Limyee.Extensibility;
using Limyee.Extensibility.Api.Entities.Version1;
using Limyee.Extensibility.Api.Version1;
using Limyee.Extensibility.Content.Version1;
using IContent = Limyee.Extensibility.Content.Version1.IContent;
namespace Samples.Links
{
public class LinkItemContentType : IContentType, ISearchableContentType
{
IContentStateChanges _contentState = null;
#region IPlugin Members
public string Description
{
get { return "Items in a Links collection"; }
}
public void Initialize()
{
}
public string Name
{
get { return "Link Items"; }
}
#endregion
#region IContentType Members
public Guid[] ApplicationTypes
{
get { return new Guid[] { ContentTypes.LinksApplicationId }; }
}
public void AttachChangeEvents(IContentStateChanges stateChanges)
{
_contentState = stateChanges;
}
public Guid ContentTypeId
{
get { return ContentTypes.LinksItemId; }
}
public string ContentTypeName
{
get { return "Links Item"; }
}
public IContent Get(Guid contentId)
{
return LinksData.GetLink(contentId);
}
#endregion
#region ISearchableContentType
public void SetIndexStatus(Guid[] contentIds, bool isIndexed)
{
LinksData.UpdateStatus(contentIds, isIndexed);
}
public IList<SearchIndexDocument> GetContentToIndex()
{
var docs = new List<SearchIndexDocument>();
var links = LinksData.ListLinks().Where(link => !link.IsIndexed);
foreach (var link in links)
{
if (link == null) { continue; }
var doc = Apis.Get<ISearchIndexing>().NewDocument(link.ContentId, link.ContentTypeId, "linkitem", link.Url, link.HtmlName("web"), link.HtmlDescription("web"));
doc.AddField("date", Apis.Get<ISearchIndexing>().FormatDate(link.CreatedDate));
docs.Add(doc);
}
return docs;
}
public int[] GetViewSecurityRoles(Guid contentId)
{
var content = LinksData.GetLink(contentId);
if (content == null) { return new int[] { }; }
if (content.Application == null) { return new int[] { }; }
return Apis.Get<IRoles>().Find("Registered Users").Select(r => r.Id.GetValueOrDefault()).ToArray();
}
public string GetViewHtml(IContent content, Target target)
{
if (content == null) { return null; }
var user = Apis.Get<IUsers>().Get(new UsersGetOptions { Id = content.CreatedByUserId });
var author = String.Format(@"<a href=""{0}"" class=""internal-link view-user-profile""><span></span>{1}</a>", Apis.Get<IHtml>().EncodeAttribute(user.ProfileUrl), Apis.Get<IHtml>().Encode(user.DisplayName));
var appLink = content.Application != null
? String.Format(@"<a href=""{0}"">{1}</a>", Apis.Get<IHtml>().EncodeAttribute(content.Application.Url), content.Application.HtmlName(target.ToString()))
: String.Empty;
var groupLink = content.Application != null && content.Application.Container != null
? String.Format(@"<a href=""{0}"">{1}</a>", Apis.Get<IHtml>().EncodeAttribute(content.Application.Container.Url), content.Application.Container.HtmlName(target.ToString()))
: String.Empty;
return String.Format(@"
<div class=""abbreviated-post-header""></div>
<div class=""abbreviated-post ui-searchresult"">
<div class=""post-metadata"">
<ul class=""property-list"">
<li class=""property-item date"">{0}</li>
<li class=""property-item author"">
<span class=""user-name"">{1}</span>
</li>
<li>
<ul class=""details"">
<li class=""property-item type""></li>
</ul>
</li>
</ul>
</div>
<h4 class=""post-name"">
<a class=""internal-link view-post"" title=""{3}"" href=""{4}"">
{2}
</a>
</h4>
<div class=""post-summary"">{5}</div>
<div class=""post-application"">
{6}
{7}
</div>
</div>
<div class=""abbreviated-post-footer""></div>",
Apis.Get<ILanguage>().FormatDate(content.CreatedDate),
author,
content.HtmlName("web"),
content.HtmlName("web"),
Apis.Get<IHtml>().EncodeAttribute(content.Url),
content.HtmlDescription("web"),
appLink,
groupLink);
}
public bool IsCacheable
{
get { return true; }
}
public bool VaryCacheByUser
{
get { return true; }
}
#endregion
}
}