Simple Guide for Creating an Azure AI Search Index in Xperience by Kentico

Learn how to set up an Azure AI Search index in Xperience by Kentico with this step-by-step guide. From project configuration to search strategy implementation, this post walks you through the integration process using .NET 8.0, Visual Studio, and the Kentico Xperience Azure Search NuGet package, ensuring optimized search functionality for your website.

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.

Setting up the Project Configuration

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.

1. Install the Azure AI Search Package for Xperience by Kentico

There are a few ways to install the package:

  1. Using the .NET CLI: Open the .NET CLI in the project and execute the following command

				
					dotnet add package Kentico.Xperience.AzureSearch
				
			
  1. Using Visual Studio: If Visual Studio is being used, navigate to Tools > NuGet Package Manager > Manage NuGet Packages for Solution…; from there, search for “Kentico.Xperience.AzureSearch”, select your project, and click the “Install” button.

Success! The Azure AI Search package for Xperience by Kentico is now installed on the project.

2. Add Kentico Azure AI Search to Your Program

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.

The image shows a clean dashboard with options grouped under: Channels: "Azure Search Test" Content Management: "Content hub," "Media libraries" Digital Marketing: "Contact groups," "Forms" Development: Highlighted "Azure AI Search" Configuration: "Channel management," "Email templates" The interface is user-friendly, with a "GA" icon at the bottom left.

Configure the Azure AI Search Module to Build the Index

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:

  • Adding Azure Keys to User Secrets: Securely storing Azure AI Search credentials.
  • Creating a Search Strategy: Building a strategy that aligns with the content types and search model.
  • Finalizing Search Index Setup in Xperience: Completing the index configuration to ensure it’s ready for seamless integration.

By the end of this process, the Azure AI Search service will be fully connected and ready to handle search queries within the application.

1. Add Azure Keys to User Secrets

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:

  • “SearchServiceEndPoint”: Overview > Url
The image shows an Azure portal interface, specifically for managing an Azure AI Search service. On the left, there's a navigation panel with options like "Overview," "Activity log," "Access control (IAM)," "Tags," and "Search management" with sub-options like "Indexes" and "Indexers." The main section highlights "Overview" with details about the service, including resource group, location, subscription, status, and URL. There's also a section for getting started with options to "Connect your data," "Explore your data," and "Monitor and scale."
  • “SearchServiceAdminApiKey”: Settings > Keys > Primary admin key
Screenshot of a minimal webpage layout with a search bar labeled 'Search' and a section labeled 'Tagline,' followed by an empty space. The footer contains links such as 'Privacy,' 'Terms of Use,' 'Support,' and 'Help.'
  • “SearchServiceQueryApiKey”: Settings > Keys > Manage query keys
The image shows the "API Access Control" settings page in a cloud management interface. It highlights the "Keys" section where the user can manage admin keys and query keys. There is a "Manage admin keys" section with options to regenerate both the primary and secondary admin keys, and a "Manage query keys" section with a key field, showing a partially hidden key represented by asterisks, along with a copy icon next to it. The "Keys" tab is selected in the left-hand navigation panel.

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.

2. Creating a Search Strategy

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<XperienceAzureExampleModel>
{
    public override async Task<IAzureSearchModel> 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<NewsDetail>);

                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<HomePage>);

                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<XperienceAzureExampleStrategy, XperienceAzureExampleModel>(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.

3. Finalizing Search Index Setup in Xperience

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.

Screenshot of a form interface with fields for input, including a 'Submit' button. The form includes multiple empty sections and input areas, with a footer containing a disclaimer or copyright notice.

In the Azure AI Search module, the index can now be rebuilt by clicking the “Rebuild” icon.

The image shows a table view of an index configuration in a web interface. The table includes the following columns: ID: The index ID is listed as "1." Name: The name of the index is "example-index." Channel: The channel is labeled as "IntegrisInsuranceAgency." Index Strategy: The indexing strategy is "XperienceAzureExampleStrategy." Entries: There are "2" entries indexed. Actions: The row includes an action section with two icons: a circular arrow for rebuilding the index (hovering over it shows a tooltip with the label "Rebuild"), and a trash bin icon for deleting the index. This view provides an overview of the index settings with the option to rebuild or delete the index.

Returning to the Azure AI Search service, navigate to Search Management> Indexes. The index should now appear, matching the name specified in Xperience.

The image displays a section of a web interface for managing search indexes. It shows the "Indexes" tab under the "Search management" section in the left-hand navigation panel. In the main content area, there is a table with columns for "Name," "Document count," "Vector index size," and "Total storage size." The index listed is named "example-index," which currently has 0 documents, 0 bytes for both vector index size and total storage size. There are options at the top of the table to "Add index," "Refresh," and "Delete."

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.

The image displays a JSON output in a search results panel. The output contains metadata related to the search index example-index from an Azure search service. The results show two indexed documents, and the relevant details include: Document 1: Title: "Home Test" Content: "A short metadata description for the home page." URL: "~/" ContentTypeName: "AzureSearchTest.HomePage" LanguageName: "en" ItemGuid: "9003b5f7-81f5-4be8-be0b-1590a16aa1d1" ObjectID: "9003b5f7-81f5-4be8-be0b-1590a16aa1d1" Search Score: 1 Document 2: Title: "Test News Detail Page" Content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vestibulum cursus tristique." URL: "~/test-news-detail-page" ContentTypeName: "AzureSearchTest.NewsDetail" LanguageName: "en" ItemGuid: "18df5d1e-7578-4e36-b2b7-7fb09d894da1" ObjectID: "18df5d1e-7578-4e36-b2b7-7fb09d894da1" Search Score: 1 The data is pulled from the Azure search service for the specified index and displayed in a structured JSON format.

Final Thoughts

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.

About the Author

Parker Ovadek

As an athlete, Parker’s first desire was to be in the Sports Management field. However, during his Sophomore year in high school, he found another passion—computers. His hobby of playing video games on a console led him to venture into PC gaming and eventually into building his own machines; he’s been hooked ever since! After high school, Parker earned his degree in Information Systems from Grand Valley State University. Outside of working hours, you’ll most likely find him on a golf course!

Migrate to Xperience by Kentico

We can help make your migration easy.

Subscribe to Our Blog

Stay up to date on what BizStream is doing and keep in the loop on the latest in marketing & technology.