Advertisement

#10 Displaying the Search Results

In this article we will create a razor page that we can use to add to, delete from, and clear our Lucene.Net search index. Once we have that in place and we have created our index we will then modify our search page to actually perform and display the search results. And finally we will modify our read page so that when a user clicks on a search result they will actually be able to read the article they have selected.

Injecting our search manager

  • WebUi
    • Startup.cs

As we have done several times in the past it is now time to modify our startup class so that we are able to inject our search manager into any of our pages that need it (a).

Startup.cs

...
using WebUi.Features.Search;
...
namespace WebUi
{
    public class Startup
    {
        ...
        public void ConfigureServices(IServiceCollection services)
        {
            ...
            services.AddTransient<ISearchManager, SearchManager>();
            ...
        }
        ...
    }
}
(a) Adding the code that allows us to inject the search manager into whichever pages need it.

Testing the search manager

  • WebUi
    • Pages
      • Lucene.cshtml.cs

In the previous article we added all the functionality that we currently need and now it is time to be able to check and see if everything is working the way it is supposed to be. First off we will create the code behind for a new razor page (b).

Index.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
using WebUi.Domain;
using WebUi.Features.Search;
using WebUi.Features.Search.Searchables;
using WebUi.Infrastructure;

namespace WebUi.Pages
{
    public class IndexModel : PageModel
    {
        private readonly IDomainRepository _domainRepository;
        private readonly ISearchManager _searchManager;
        private readonly IViewRenderer _viewRenderer;

        public IndexModel(IDomainRepository domainRepository, ISearchManager searchManager, IViewRenderer viewRenderer)
        {
            _domainRepository = domainRepository;
            _searchManager = searchManager;
            _viewRenderer = viewRenderer;
        }

        public string Action { get; set; }

        public void OnGet()
        {
            Action = "Get";
        }

        public async Task OnPostIndexAsync()
        {
            Action = "index";

            var articles = await _domainRepository.Articles.ToListAsync();
            var searchables = articles.Select(x => new SearchableArticle(x, _viewRenderer)).ToArray<Searchable>();

            _searchManager.AddToIndex(searchables);
        }

        public void OnPostClear()
        {
            Action = "clear";

            _searchManager.Clear();
        }

        public async Task OnPostDeleteAsync()
        {
            Action = "delete";

            var article = await _domainRepository.Articles.FirstAsync();
            var searchable = new SearchableArticle(article, _viewRenderer);
            _searchManager.DeleteFromIndex(searchable);
        }
    }
}
(b) The code behind for our new Lucene razor page.
  • WebUi
    • Pages
      • Lucene.cshtml

Next up is the view for the page (c). Its not much to look at but it will give us the ability to interact with our search manager.

Index.cshtml

@page
@model IndexModel
@{
    ViewData["Title"] = "Lucene";
}

<h2>@Model.Action</h2>

<form asp-page="Index" method="post">
    <button type="submit" asp-page-handler="Index">Index</button>
</form>

<form asp-page="Index" method="post">
    <button type="submit" asp-page-handler="Delete">Delete</button>
</form>

<form asp-page="Index" method="post">
    <button type="submit" asp-page-handler="Clear">Clear</button>
</form>
(c) Using these forms will allow us to interact with our search manager.
Advertisement

If we press the index button now we should see a few files being created in our Lucene_Index folder (d).

Image showing the files that were created in the index folder when we pressed the index button.
(d) Image showing the files that were created in the index folder when we pressed the index button.

Time to actually search the index and display the results

  • WebUi
    • Pages
      • Search.cshtml.cs

Now we will return to our search page and modify it so that an actual call to the Search method of our search manager will be made and the results, if any, will be parsed (e).

Search.cshtml.cs

...
using System.Linq;
using WebUi.Features.Search.Searchables;

namespace WebUi.Pages
{
    public class SearchModel : PageModel
    {
        private readonly ISearchManager _searchManager;

        public SearchModel(ISearchManager searchManager)
        {
            _searchManager = searchManager;
        }
        ...
        public void OnGet()
        {
            Results = _searchManager.Search(Search, 0, 100, Searchable.AnalyzedFields.Values.ToArray());

            foreach (var result in Results.Data)
            {
                result.Parse(x =>
                    {
                        result.DescriptionPath = x.Get(Searchable.FieldStrings[Searchable.Field.DescriptionPath]);
                        result.LinkText = x.Get(Searchable.FieldStrings[Searchable.Field.Title]);
                        result.LinkHref = x.Get(Searchable.FieldStrings[Searchable.Field.Href]);
                    });
            }
        }
    }
}
(e) Modifying our search page code behind so that an actual call to the search method is made and the results are parsed.

Modifying our read page

  • WebUi
    • Pages
      • Articles
        • Read.cshtml

When the search results are displayed we will be allowing the user to click on one and be directed to the read page to be able to read the article. For this to work we need to update our read page so that it will be accepting an id parameter (f).

Read.cshtml

@page "{id:int}"
...
(f) Updating the read page so that it will accept an id parameter.
  • WebUi
    • Pages
      • Articles
        • Read.cshtml.cs

Last but not least we need to update the code behind so that a request is made to the database and depending on the result of that request the appropriate response is returned (g).

Read.cshtml.cs

using Microsoft.AspNetCore.Mvc;
...
namespace WebUi.Pages.Articles
{
    public class ReadModel : PageModel
    {
        ...
        [BindProperty(SupportsGet = true)] public int Id { get; set; }
        ...

        public async Task<IActionResult> OnGetAsync()
        {
            var article = await _repository.Articles
                .FirstOrDefaultAsync(x => x.Id == Id);

            if (article == null)
            {
                return NotFound();
            }

            Author      = article.Author;
            Created     = article.Created;
            Id          = article.Id;
            Title       = article.Title;

            ContentPath = $"Content{Id}.cshtml";
            IntroPath = $"Intro{Id}.cshtml";

            return Page();
        }
    }
}
(g) Updating the get method to make a database request and return the appropriate response.
Exciton Interactive LLC
Advertisement