Adding Search to Blazor Applications
Plenty going on in the backend. Take a look at how this developer used Azure AD to add a search function to his open source project.
Join the DZone community and get the full member experience.
Join For FreeAs my Blazor demo application supports now Azure AD I took the next step and implemented search using Azure Search service. This blog post shows how to add search capabilities to Blazor application using Azure AD-protected Azure Functions back-end and Azure Search service.
Source code available! Source code for my Blazor demo solution is available at my GitHub repository peipman/BlazorDemo. Feel free to go through the code or make it work on your own Azure environment. I expect you to keep the code open while going through this blog post. Where adequate I also have links to specific files in solution provided.
Azure Search is powerful search solution for small and big corporate sites. As all other parts of my solution are implemented using Azure services I decided to keep the same pattern also with search. Here's the high-level view to mu solution with search added.
Although I first wanted to go with pure Blazor implementation of Azure Search client, it turned out to be impossible. Blazor makes all requests to an external system exactly like the browser does. It means that first there's OPTIONS request to check CORS stuff. For most of requests, the answer is negative. It's possible to use a query key to send queries to search index but in big part this is all we can do. Other actions expect web application to know search service administration key and this is considered as a high risk. Microsoft suggests to keep Azure Search behind some server-side service for security reasons.
Setting Up Azure Search
Before we start with code we need to create Azure Search service and index for books. I have the free pricing tier. The following image shows my search index. I called it "books". For CORS you can enable access for all locations for testing. For live sites it is recommended to configure it if browser access is needed. The following screenshot shows my books index.
To communicate with Azure Search we need Microsoft.Azure.Search NuGet package in BlazorDemo.AzureFunctionsBackend project. For demo purposes I added simple static class AzureSearchClient.
public static class AzureSearchClient{ private static SearchIndexClient GetClient() { return new SearchIndexClient("<service name>", "books", new SearchCredentials("<service key>")); } public static async Task<PagedResult<Book>> Search(string term, int page) { var searchParams = new SearchParameters(); searchParams.IncludeTotalResultCount = true; searchParams.Skip = (page - 1) * 10; searchParams.Top = 10; using (var client = GetClient()) { var results = await client.Documents.SearchAsync<Book>(term, searchParams); var paged = new PagedResult<Book>(); paged.CurrentPage = page; paged.PageSize = 10; paged.RowCount = (int)results.Count; paged.PageCount = (int)Math.Ceiling((decimal)paged.RowCount / 10); foreach (var result in results.Results) { paged.Results.Add(result.Document); } return paged; } } public static async Task IndexBook(Book book, TraceWriter log) { using (var client = GetClient()) { var azureBook = new { id = book.Id.ToString(), Title = book.Title, ISBN = book.ISBN }; var batch = IndexBatch.MergeOrUpload(new [] { azureBook }); await client.Documents.IndexAsync(batch); } } public static async Task RemoveBook(int id) { using (var client = GetClient()) { var batch = IndexBatch.Delete("id", new[] { id.ToString() }); await client.Documents.IndexAsync(batch); } }}
This class has four methods:
-
GetClient()
- creates new search client with information needed to communicate with books index. -
Search()
- queries search index for given term and returns paged result with books. To get better idea about how PagedResult<T> works I have blog post Paging with Entity Framework Core. For full paging sample I have sample in GitHub repository gpeipman/DotNetPaging. -
IndexBoox()
- adds or updates given book in search index. -
RemoveBook()
- removes book from search index.
For a real-life scenario, I suggest going with a better architecture and building a real client that can be injected or retrieved by the same simple service locator you build for functions.
Adding Search to Functions Backend
As the Blazor application uses search through functions we have to add new function to query search index. Other methods like Save()
and Delete
must also update search index ( Functions.cs file in BlazorDemo.AzureFunctionsBackend project).
Search function is just a wrapper between the Blazor application and Azure Search so we don't have to connect Blazor directly to Azure Search. This way, Blazor has no way of knowing about search details and, if needed, we can change the search logic without any need to deploy Blazor again. Also there's no danger that search index gets accessible to unknown users (remember, Azure Search is not protected by Azure AD).
Adding Search Box toUser Interface
The final part of work is to update UI of application and add search box with some buttons there. What we want to achieve is something as shown on following image.
Let's start with the Index page (Pages/Index.cshtml file in BlazorDemo.AdalClient project). We add search box with Search and Clear buttons right next to Add new button like shown in the code fragment below.
We bind search box field to SearchTerm property of Index page model. It is two-way binding meaning that property gets the value automatically when text in search box is changed. We also have to capture onkeyup event of search box. If the user clicked Enter button there, then we have to search books or load default list from database.
New events are here ( Pages/Index.cshtml.cs file in BlazorDemo.AdalClient project).
If you go through Index page you will see how current page and search term are always available through routes. Paging works also with search results.
This is how Blazor books database looks after adding search.
Wrapping Up
Azure Search is a powerful search service for websites and different types of applications. For Blazor applications it works best when used behind the API layer — be it ASP.NET Core Web API or Azure Functions. This blog post showed how to build search to Blazor applications using Azure Functions and Azure Search services. Together with Azure AD it takes some effort to configure services on Azure but we have less hassle on code level later.
Published at DZone with permission of Gunnar Peipman, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments