World is now on Opti ID! Learn more

Ravindra S. Rathore
Sep 22, 2019
  56
(0 votes)

Rebuild the index for selected sites in Episerver Find | Admin Tool

Hi

Last Friday, I wrote a blog post related to "Reindex a target site in Find" using is works job. It works well but you need to update the site definition every time when you want to rebuild the indexes for any site.

So I received some feedback to convert it to Episerver Admin Tool and now I converted it to Episerver Admin Tool. Where you can rebuild the indexes for selected sites.

Here is the final structure of my solution.

To create a new GUI Plugin Episerver provide a template for Webforms but not for MVC so you need to create it manually. Below I mentioned the steps for creating a GUI plugin using MVC.

FYI - You can refer this blog post to create a custom GUI Plugin using MVC

Create a Controller

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using EPiServer.Find.Cms;
using EPiServer.Find.Helpers.Text;
using EPiServer.PlugIn;
using EPiServer.ServiceLocation;
using EPiServer.Web;
using ReindexTargetSite_AdminTool.AdminTools.FindIndexPlugin.ViewModels;

namespace ReindexTargetSite_AdminTool.AdminTools.FindIndexPlugin
{
    [GuiPlugIn(
        Area = PlugInArea.AdminMenu,
        Url = "/custom-plugins/my-plugin",
        DisplayName = "Rebuild Find Index")]
    [Authorize(Roles = "CmsAdmins")]
    public class RebuildFindIndexController : Controller
    {
        public static string Message { get; set; }
        public static string ExecutionCompleteMessage { get; set; }

        private ISiteDefinitionRepository _siteDefinitionRepository;
        public RebuildFindIndexController(ISiteDefinitionRepository siteDefinitionRepository)
        {
            _siteDefinitionRepository = siteDefinitionRepository ?? ServiceLocator.Current.GetInstance<ISiteDefinitionRepository>();

        }
        public ActionResult Index()
        {
            var siteDefinitions = _siteDefinitionRepository.List();
            var siteList = new List<SiteDefinition>();
            if (siteDefinitions.Any())
            {

                foreach (var site in siteDefinitions)
                {
                    siteList.Add(site);
                }

            }

            var model = new RebuildFindIndexViewModel
            {
                Sites = siteList
            };
            return View("~/AdminTools/FindIndexPlugin/Views/Index.cshtml", model);
        }

        [HttpPost]
        public async Task<ActionResult> InitiateRebuildIndex(Guid[] selectedObjects)
        {
            Message = null;
            ExecutionCompleteMessage = null;

            string selectedSite = Request.Form["SelectedSite"];

            _ = Task.Run(() => StartRebuild(selectedObjects));
            return View("~/AdminTools/FindIndexPlugin/Views/Index.cshtml");
        }

        private void StartRebuild(Guid[] selectedSite)
        {
            foreach (var site in selectedSite)
            {
                SiteDefinition.Current = _siteDefinitionRepository.List().FirstOrDefault(i => i.Id.Equals(site));

                if (SiteDefinition.Current != null && !string.IsNullOrEmpty(SiteDefinition.Current.Name))
                {
                    var statusReport = new StringBuilder();

                    // ReIndex the indexes for the sites
                    ContentIndexer.ReIndexResult reIndexResult = ContentIndexer.Instance.ReIndex(
                        status =>
                        {
                            if (status.IsError)
                            {
                                string errorMessage = status.Message.StripHtml();
                                if (errorMessage.Length > 0)
                                    statusReport.Append($"{errorMessage}");
                            }

                            Message =
                                $"Indexing job [{(SiteDefinition.Current.Name)}] [content]: {status.Message.StripHtml()}";
                        },
                        () => false);
                }
            }

            ExecutionCompleteMessage = Message;
        }
        [HttpGet]
        public ActionResult GetMessage()
        {
            return Json(new { RunningMessage = Message, StopExecution = ExecutionCompleteMessage }, JsonRequestBehavior.AllowGet);
        }
    }
}

Create a ViewModel

using System;
using System.Collections.Generic;
using EPiServer.Web;

namespace ReindexTargetSite_AdminTool.AdminTools.FindIndexPlugin.ViewModels
{
    public class RebuildFindIndexViewModel
    {
        public IEnumerable<Guid> SelectedSites { get; set; }
        public IEnumerable<SiteDefinition> Sites { get; set; }
    }
}

Create a View

@using System.Web.Mvc
@using System.Web.Mvc.Html
@inherits System.Web.Mvc.WebViewPage<ReindexTargetSite_AdminTool.AdminTools.FindIndexPlugin.ViewModels.RebuildFindIndexViewModel>
@{
    Layout = null;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript">
    var messageInterval = setInterval(function () {
        $.get('/custom-plugins/my-plugin/get-message').done(function (result) {
            $(".job-started").show();
            if (result.StopExecution == null) {
                $('#runningStatus').html(result.RunningMessage);

            } else {
                $('#runningStatus').html(result.StopExecution);
                clearInterval(messageInterval);
                $(".job-started").html("Index rebuild successfully");
                $("#runningStatus").hide();
            }
        });
    }, 10000)
</script>
@if (Model != null && Model.Sites != null && Model.Sites.Any())
{
    <h2>Site Listing</h2>

    using (Html.BeginForm("InitiateRebuildIndex", "RebuildFindIndex", FormMethod.Post))
    {

        foreach (var site in Model.Sites)
        {
            <input type="checkbox" title="@site.Name" name="selectedObjects" value="@site.Id">
            <label for="selectedObjects">@site.Name</label>
            <br />

        }
        @*@Html.DropDownList("SelectedSite", new SelectList(Model.Sites, "Value", "Text"))*@
        <input type="submit" value="Rebuild" />
    }
}
else
{
    <h2 class="job-started">Schedule job started</h2>
    <div id="runningStatus"></div>
}

Create an initialization Module 

using System.Web.Mvc;
using System.Web.Routing;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;

namespace ReindexTargetSite_AdminTool.AdminTools.FindIndexPlugin.Initialization
{
    [InitializableModule]
    [ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
    public class PluginRouteInitialization : IInitializableModule
    {
        public void Initialize(InitializationEngine context)
        {
             RouteTable.Routes.MapRoute(
             null,
             "custom-plugins/my-plugin",
             new { controller = "RebuildFindIndex", action = "Index" });
             RouteTable.Routes.MapRoute(
                 null,
                 "custom-plugins/my-plugin/initiate-rebuild-index",
                 new { controller = "RebuildFindIndex", action = "InitiateRebuildIndex" });
             RouteTable.Routes.MapRoute(
                 null,
                 "custom-plugins/my-plugin/get-message",
                 new { controller = "RebuildFindIndex", action = "GetMessage" });
        }

        public void Uninitialize(InitializationEngine context)
        {
            //Add uninitialization logic
        }
    }
}

That's it from a code point of view. Now you just need to login into you Episerver and go to Admin view and select the new plugin "Rebuild Find Index"

Now select the sites and click on the "Rebuild" button.

It will rebuild the indexes for the selected sites.

FYI - I will add the link once i upload this to Github.

I hope it helps

Thanks

Ravindra S. Rathore

Sep 22, 2019

Comments

Please login to comment.
Latest blogs
Make Global Assets Site- and Language-Aware at Indexing Time

I had a support case the other day with a question around search on global assets on a multisite. This is the result of that investigation. This co...

dada | Jun 26, 2025

The remote server returned an error: (400) Bad Request – when configuring Azure Storage for an older Optimizely CMS site

How to fix a strange issue that occurred when I moved editor-uploaded files for some old Optimizely CMS 11 solutions to Azure Storage.

Tomas Hensrud Gulla | Jun 26, 2025 |

Enable Opal AI for your Optimizely products

Learn how to enable Opal AI, and meet your infinite workforce.

Tomas Hensrud Gulla | Jun 25, 2025 |

Deploying to Optimizely Frontend Hosting: A Practical Guide

Optimizely Frontend Hosting is a cloud-based solution for deploying headless frontend applications - currently supporting only Next.js projects. It...

Szymon Uryga | Jun 25, 2025

World on Opti ID

We're excited to announce that world.optimizely.com is now integrated with Opti ID! What does this mean for you? New Users:  You can now log in wit...

Patrick Lam | Jun 22, 2025

Avoid Scandinavian Letters in File Names in Optimizely CMS

Discover how Scandinavian letters in file names can break media in Optimizely CMS—and learn a simple code fix to automatically sanitize uploads for...

Henning Sjørbotten | Jun 19, 2025 |