Xperience by Kentico is the latest modern content management system that Kentico has released. It immediately stands out with its sleek, modern interface, fast navigation, and powerful features. One key feature is the ability to integrate with Azure AI Search. This post outlines the steps to configure a project for Azure AI Search integration and set up the Azure AI Search module in the admin to build a search index using content types defined in Xperience.
Below is what will be used to implement this feature:
The initial steps focus on configuring the project to make Azure AI Search accessible within the Xperience admin interface. This involves installing the Azure Search package for Xperience by Kentico, setting it up in the Program.cs file, and ensuring it’s recognized in the Xperience admin.
There are a few ways to install the package:
dotnet add package Kentico.Xperience.AzureSearch
Success! The Azure AI Search package for Xperience by Kentico is now installed on the project.
Next, open the Program.cs file and call the IServiceCollection extension method AddKenticoAzureSearch, passing it the ConfigurationManager. The line of code should look like this:
builder.Services.AddKenticoAzureSearch(builder.Configuration);
The project can now be run. Upon accessing the Xperience admin interface, a new module under Development titled “Azure AI Search” should now be visible.
With the program configured to access the Azure AI Search module, the next step is connecting the Azure AI Search service to the application.
These steps involve:
By the end of this process, the Azure AI Search service will be fully connected and ready to handle search queries within the application.
If a 500 error occurs when accessing the ‘Azure AI Search’ module, it is likely due to missing settings from the search service. To resolve this, right-click the project in Visual Studio and select ‘Manage User Secrets.’ Then, paste the following keys:
{
"CMSAzureSearch": {
"SearchServiceEndPoint": "",
"SearchServiceAdminApiKey": "",
"SearchServiceQueryApiKey": ""
}
}
IMPORTANT: The names of the keys must match exactly what they are named above.
To retrieve the values for these keys, consult the following settings in the Azure AI Search service:
Note: If a query key does not already exist, be sure to create one by clicking the “Add” button, entering a name, and clicking “Done.” This should automatically generate a key to be copied.
After rebuilding the project, returning to the admin, and accessing the module, the error should no longer appear.
The next step involves developing a strategy for building the search index, ensuring that the fields of the content types are properly mapped. For this example, the NewsDetail and Homepage content types from my “Azure Search Test” Xperience channel will be used.
Begin by adding two files to your project: one for the search model and one for the search strategy. In this example, those files will be named XperienceAzureExampleModel and XperienceAzureExampleStrategy, respectively.
The model will inherit from the BaseAzureSearchModel that the Xperience Azure Search package provides.
using Azure.Search.Documents.Indexes;
using Kentico.Xperience.AzureSearch.Indexing;
namespace AzureSearchTest.Web.Search.Models;
public class XperienceAzureExampleModel : BaseAzureSearchModel
{
[SearchableField]
public string Content { get; set; }
[SearchableField]
public string Title { get; set; }
// Add extra fields as needed here
}
The strategy will inherit from BaseAzureSearchIndexingStrategy<TSearchModel> provided by the Xperience Azure Search package, with the model created earlier used as the TSearchModel. Next, implement the MapToAzureSearchModelOrNull method. This method checks whether the incoming IIndexEventItemModel parameter matches one of the content types intended for inclusion in the search index. If a match is found, the relevant fields from the content type will be mapped to the corresponding fields in the TSearchModel, and the model will be returned.
public class XperienceAzureExampleStrategy(
IWebPageUrlRetriever urlRetriever,
IWebPageQueryResultMapper webPageMapper,
IContentQueryExecutor queryExecutor
) : BaseAzureSearchIndexingStrategy
{
public override async Task MapToAzureSearchModelOrNull(IIndexEventItemModel item)
{
var model = new XperienceAzureExampleModel();
// IIndexEventItemModel could be a reusable content item or a web page item, so we use
// pattern matching to get access to the web page item specific type and fields
if (item is IndexEventWebPageItemModel indexedPage)
{
if (string.Equals(item.ContentTypeName, NewsDetail.CONTENT_TYPE_NAME, StringComparison.OrdinalIgnoreCase))
{
var query = new ContentItemQueryBuilder()
.ForContentType(
NewsDetail.CONTENT_TYPE_NAME,
config =>
config
.WithLinkedItems(4)
.ForWebsite(indexedPage.WebsiteChannelName)
.Where(where => where.WhereEquals(nameof(WebPageFields.WebPageItemGUID), indexedPage.ItemGuid))
.TopN(1))
.InLanguage(indexedPage.LanguageName);
var result = await queryExecutor.GetWebPageResult(query, webPageMapper.Map);
var page = result.FirstOrDefault();
if (page is null)
{
return null;
}
try
{
model.Url = (await urlRetriever.Retrieve(
indexedPage.WebPageItemTreePath,
indexedPage.WebsiteChannelName,
indexedPage.LanguageName)).RelativePath;
}
catch (Exception)
{
// Retrieve can throw an exception when processing a page update AzureSearchQueueItem
// and the page was deleted before the update task has processed. In this case, upsert an
// empty URL
}
// Set the search model's `Title` to the desired field on the content item
model.Title = page?.NewsTitle ?? string.Empty;
// Set the search model's `Content` to the desired field on the content item
model.Content = page?.NewsArticle ?? string.Empty;
}
else if (string.Equals(item.ContentTypeName, HomePage.CONTENT_TYPE_NAME, StringComparison.OrdinalIgnoreCase))
{
var query = new ContentItemQueryBuilder()
.ForContentType(
HomePage.CONTENT_TYPE_NAME,
config =>
config
.WithLinkedItems(4)
.ForWebsite(indexedPage.WebsiteChannelName)
.Where(where => where.WhereEquals(nameof(WebPageFields.WebPageItemGUID), indexedPage.ItemGuid))
.TopN(1))
.InLanguage(indexedPage.LanguageName);
var result = await queryExecutor.GetWebPageResult(query, webPageMapper.Map);
var page = result.FirstOrDefault();
if (page is null)
{
return null;
}
// Set the search model's `Title` to the desired field on the content item
model.Title = page?.MetadataTitle ?? string.Empty;
// Set the search model's `Content` to the desired field on the content item
model.Content = page?.MetadataDescription ?? string.Empty; }
else
{
return null;
}
}
else
{
return null;
}
return model;
}
}
After implementing the strategy, return to the Program.cs file and update the previous line of code that was implemented earlier to look like this:
builder.Services.AddKenticoAzureSearch(builder =>
{
builder.RegisterStrategy(nameof(XperienceAzureExampleStrategy));
}, builder.Configuration);
With the search strategy now successfully implemented, the next step is to configure the search index in the Xperience admin, preparing it for the indexing process. This will ensure everything is ready for building the index and integrating your search functionality seamlessly.
To begin this final step, navigate back to the Azure AI Search module in the Xperience admin. Click the “Create Index” button, then follow these steps: enter the Included Path, select the Included content types (matching those from the search strategy), specify the Index Name, choose the Indexed Languages, select the Channel Name, and finally, choose the indexing strategy implemented earlier from the Indexing Strategy dropdown. Be sure to save the path and then save the index.
In the Azure AI Search module, the index can now be rebuilt by clicking the “Rebuild” icon.
Returning to the Azure AI Search service, navigate to Search Management> Indexes. The index should now appear, matching the name specified in Xperience.
The contents of the index should now display only the content types included in the search strategy that have corresponding pages within the Xperience channel.
By following these steps, a fully functional integration between Xperience by Kentico and Azure AI Search has been established. The project configuration, search strategy implementation, and search index setup in the Xperience admin now allow content types to be indexed and searched efficiently. This integration not only enhances the search capabilities of the application but also demonstrates the flexibility and power of Xperience when paired with Azure AI Search. With everything in place, the application is ready to handle and optimize search queries, providing users with fast and relevant search results.
We love to make cool things with cool people. Have a project you’d like to collaborate on? Let’s chat!
Stay up to date on what BizStream is doing and keep in the loop on the latest in marketing & technology.