Umbraco 13后台搜索重写:能否替换Examine驱动的SearchAll API调用?
重写Umbraco 13后台Examine搜索功能的实现方案
完全可以重写Umbraco 13后台的搜索逻辑,替换默认的/umbraco/backoffice/umbracoapi/entity/SearchAll接口调用。下面是几种可行的实现方式:
1. 覆盖默认的EntityApiController
Umbraco的后台API基于ASP.NET Core WebAPI,默认搜索逻辑在EntityApiController的SearchAll方法中。你可以创建自定义控制器继承该类,重写SearchAll方法实现自定义Examine搜索。
实现步骤:
- 创建自定义控制器,标记
[PluginController("Umbraco")]确保Umbraco优先使用该控制器 - 注入
IExamineManager和必要服务,实现自定义搜索逻辑 - 将Examine搜索结果转换为后台所需的
EntitySearchResultModel格式
using Umbraco.Cms.Core.Services; using Umbraco.Cms.Web.BackOffice.Controllers; using Umbraco.Cms.Web.Common.Attributes; using Examine; using Umbraco.Cms.Core.Models.ContentEditing; [PluginController("Umbraco")] public class CustomEntityApiController : EntityApiController { private readonly IExamineManager _examineManager; private readonly IContentTypeService _contentTypeService; public CustomEntityApiController( IEntityService entityService, ILocalizedTextService localizedTextService, IExamineManager examineManager, IContentTypeService contentTypeService) : base(entityService, localizedTextService) { _examineManager = examineManager; _contentTypeService = contentTypeService; } public override IEnumerable<EntitySearchResultModel> SearchAll(string query) { // 获取Examine搜索器(这里用内置的InternalSearcher,可按需替换) if (!_examineManager.TryGetSearcher("InternalSearcher", out ISearcher searcher)) return Enumerable.Empty<EntitySearchResultModel>(); // 执行自定义Examine查询 var searchResults = searcher.CreateQuery() .ManagedQuery(query) .Execute(); // 转换为后台要求的结果格式 return searchResults.Select(result => { if (int.TryParse(result.Id, out int nodeId) && Guid.TryParse(result.Fields["nodeKey"], out Guid nodeKey)) { var contentType = _contentTypeService.Get(int.Parse(result.Fields["contentTypeId"])); return new EntitySearchResultModel { Id = nodeId, Key = nodeKey, Name = result.Fields["nodeName"], Icon = contentType?.Icon ?? "icon-document", ParentId = int.Parse(result.Fields["parentId"]), Path = result.Fields["path"], EntityType = "Document" // 根据节点类型调整为Media/Member }; } return null; }).Where(model => model != null); } }
2. 使用请求拦截器(IAsyncActionFilter)
如果不想直接覆盖控制器,可以通过动作过滤器拦截目标API请求,替换搜索逻辑后直接返回结果,跳过默认控制器执行。
实现步骤:
- 实现
IAsyncActionFilter接口,检查请求路径是否为目标API - 提取查询参数,执行自定义Examine搜索
- 构造结果并设置
context.Result,终止默认流程
using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Cms.Core.Examine; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Services; public class SearchAllInterceptorFilter : IAsyncActionFilter { private readonly IExamineManager _examineManager; private readonly IContentTypeService _contentTypeService; public SearchAllInterceptorFilter(IExamineManager examineManager, IContentTypeService contentTypeService) { _examineManager = examineManager; _contentTypeService = contentTypeService; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { // 匹配目标API路径 var requestPath = context.HttpContext.Request.Path; if (requestPath.Equals("/umbraco/backoffice/umbracoapi/entity/SearchAll", StringComparison.OrdinalIgnoreCase) && context.ActionArguments.TryGetValue("query", out var queryObj) && queryObj is string query) { // 执行自定义搜索 if (!_examineManager.TryGetSearcher("InternalSearcher", out ISearcher searcher)) { context.Result = new Microsoft.AspNetCore.Mvc.JsonResult(Enumerable.Empty<EntitySearchResultModel>()); return; } var searchResults = searcher.CreateQuery() .ManagedQuery(query) .Execute(); // 转换结果格式 var resultModels = searchResults.Select(result => { if (int.TryParse(result.Id, out int nodeId) && Guid.TryParse(result.Fields["nodeKey"], out Guid nodeKey)) { var contentType = _contentTypeService.Get(int.Parse(result.Fields["contentTypeId"])); return new EntitySearchResultModel { Id = nodeId, Key = nodeKey, Name = result.Fields["nodeName"], Icon = contentType?.Icon ?? "icon-document", ParentId = int.Parse(result.Fields["parentId"]), Path = result.Fields["path"], EntityType = "Document" }; } return null; }).Where(model => model != null); // 返回自定义结果,跳过默认逻辑 context.Result = new Microsoft.AspNetCore.Mvc.JsonResult(resultModels); return; } // 非目标请求,继续执行默认流程 await next(); } }
注册拦截器
通过Umbraco Composer注册过滤器:
using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Web.Common.ApplicationBuilder; public class SearchFilterComposer : IComposer { public void Compose(IUmbracoBuilder builder) { builder.Services.AddMvcOptions(options => { options.Filters.Add<SearchAllInterceptorFilter>(); }); } }
3. 自定义后台搜索前端组件(可选)
如果需要完全自定义搜索UI,可以替换Umbraco后台的默认搜索组件(Umbraco 13使用React构建后台)。通过Package Manifest注册自定义React组件,替换默认搜索框,使其调用你的自定义API而非默认接口。这种方式适合深度定制搜索UI的场景,但实现复杂度较高。
内容的提问来源于stack exchange,提问作者Funky
相关产品推荐
相关产品推荐

