Views: 556
Number of votes: 2
Average rating:

Managing Episerver Find Exceptions when querying the index

I have been working on the Episerver Find implementation here at Redweb for a client build. I was noticing that there were some errors that would occasionally happen when performing some queries against the index. After having a look around, I came across this article that gave me a solution to the issue and thought I would share the implementation into the project.

Firstly, I put a try catch around any of the Find services when they would be making a query against the index so that any errors would be caught. I can then check to see if the error is a ClientException or a ServiceException. If they are I can log the error with the exception to make sure there isn’t an issue with what we have written.

try
{
    var search = _findClient.Search<SupplierProduct>();

    if (!productCategoryId.IsNullOrWhiteSpace())
    {
        search = search.Filter(x => x.ParentCategory.Match(categoryId));
    }

    if (!string.IsNullOrWhiteSpace(queryString))
    {
        search = search.For(queryString).InField(x => x.Name);
    }

    if (!facetsList.IsNullOrEmpty())
    {
        search = search.MatchCategories(facetsList);
    }
    
    var supplierResults = search
        .ApplyBestBets()
        .UsingAutoBoost()
        .Skip((currentPage - 1) * resultsPerPage)
        .Take(resultsPerPage)
        .StaticallyCacheFor(TimeSpan.FromMinutes(1))
        .GetContentResult();

    return supplierResults;
}
catch (Exception ex) when(ex is ClientException || ex is ServiceException)
{
    Services.Episerver.Logger.Log(Level.Error, "Shop Search encountered an Episerver Find Exception", ex);
    return new EmptyContentResult<SupplierProduct>();
}

To make sure that the user has the best experience possible, a new type of content result was created. This means that if an error occurs an EmptyContentResult would be returned rather than an error. The new content result would have no results programmed set within the properties and can have the type passed into it so that it returns the correct class type for the search being performed.

public class EmptyContentResult<T> : ContentResult<T> where T : IContentData
{
    public EmptyContentResult() : base(
        Enumerable.Empty<T>(),
        new SearchResults<ContentInLanguageReference>(
            new SearchResult<ContentInLanguageReference>()
            {
                Facets = new FacetResults(),
                Hits = new HitCollection<ContentInLanguageReference>()
                {
                    Hits = Enumerable.Empty<SearchHit<ContentInLanguageReference>>().ToList()
                },
                Shards = new Shards()
            }))
    { }
}

This means that if any errors occur, although an empty page would show to the user, it would not break their view of the site and handle the error in an appropriate manner. This was very quick to implement across all the search methods on the site and also catches any of the errors that could occur out of our control.

I hope this helps some people out and I have also linked to the original source if anyone wants to look at it as well.

Hi, while exception handling is important I would disagree on the part where you claim to create better user experience by "hiding" the error from the user. I would say that you are creating bad experience and frustrating situation for the end-user. What ever they look for just returns no results (empty page or search result page saying "No results")? Why not honestly show the client that there was an error in the search and they can try the search later when the imaginary little dwarfs have corrected the astral projections that prevented the search to work ;)

Think about when you go to a web site and search for something

  • you get X results
  • you get message, sorry no results matched your query
  • you get Beep! Beep! 500 - Asteroids destroyed our search, we will fix it as soon as possible (launching rescue pods..)
  • according to your description user gets empty page

So I think telling the user there was an error on the server creates better user experience for the end user VS white page/no information that something actually went wrong.

Your code now only handles the Find related exceptions but what if there is a NullReferenceException or something else "a bug" in you code when you setup the query? Those are now bubbled up the stack and if not handled anywhere then you have the same situation as before adding the Find specific exception handling (so are you missing proper exception handling in higher the call stack? eventually (custom) error page if the exception is not handled in the code).

So it is unclear in the implementation fragment is it code from your search service implementation or block of code from your controller. If it is a service that you call from other code I would suggest to throw new Exception so that your calling code knows there was an Exception and there will be no results to show and if the caller then should show some error page or message in the search result view. Or another option is to return null to the caller and tell in the documentation that if there is an exception then the implementation will return null (and then the caller needs to have code for null check on return value - so this can always be argued to be bad practice, use exceptions for exception handling ;) )

There is a blog post about the Episerver Find exception types by Jonas Bergqvist in the Find blog.

Please login to comment.