THIS IS ARCHIVED DOCUMENTATION

LINQ QueryResults Example: Create a Basic Search Page

Coveo for Sitecore (July 2016) Coveo for Sitecore 4.1 (November 2018)

This page contains basic information on how to send a query and present you with the results.

Since this procedure will serve as the basis for the rest of the tutorial, you should keep a clean copy of it.

Basic Search Page

Start by creating a basic search page and a model that contains all the useful information needed to execute a query:

LinqBasedPageExample_1.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="LinqBasedPageExample.aspx.cs" Inherits="Tutorial.LinqBasedPageExample" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>LINQ-based Page Example</title>
</head>
<body>
    <form id="pageForm" runat="server">
        <div class="searchSection">
            <asp:Literal Text="Query: " runat="server" />
            <asp:TextBox ID="Querybox" runat="server" />
            <asp:Button type="submit" Text="Run Query" runat="server" />
        </div>
    </form>
</body>
</html>

Server-Side Code Reference

This specifies which file to use as server-side code. If you change your file name, remember to change it here too.

LinqBasedPageExample_1.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="LinqBasedPageExample.aspx.cs" Inherits="Tutorial.LinqBasedPageExample" %>

You can change this title to your liking, as it’s the title shown in the browser tab when the page is opened.

LinqBasedPageExample_1.aspx

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>LINQ-based Page Example</title>
</head>

Basic Form

This form contains the information sent to the server when the client sends a query.

The Querybox TextBox contains the client query.

The submit button ensures the client can click a button to send a query.

The searchSection class can be styled to your liking. It’s currently shown solely to clarify this div intention.

Most of the component this tutorial implements are going to be added to this form.

LinqBasedPageExample_1.aspx

<form id="pageForm" runat="server">
    <div class="searchSection">
        <asp:Literal Text="Query: " runat="server" />
        <asp:TextBox ID="Querybox" runat="server" />
        <asp:Button type="submit" Text="Run Query" runat="server" />
    </div>
</form>

Base Server-Side File

These imports ensure that you have all the necessary assemblies for the full tutorial. Feel free to remove any of them if you don’t need them or you think they’re superfluous.

LinqBasedPageExample_1.aspx.cs

namespace Tutorial {
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using Coveo.Framework.SearchService;
    using Coveo.SearchProvider.Linq;
    using Coveo.SearchProvider.LinqBase;
    using Sitecore.ContentSearch;
    using Sitecore.ContentSearch.Linq;
    using Sitecore.ContentSearch.SearchTypes;
  
    public partial class LinqBasedPageExample : Page {
  
    }
}

Search Model

While this section may seem like it could be simpler for your current page, it will serve as a good basis for the rest of the tutorial.

In your server-side code, after the LinqBasedPageExample class, create a model that contains all the useful information to execute a search query.

LinqBasedPageExample_1.aspx.cs

public class SearchModel {
    public string Query { get; set; }
    public SearchModel() {
        Query = "";
    }
}

Add a method in the LinqBasedPageExample class that maps the Querybox control value to the model.

LinqBasedPageExample_1.aspx.cs

private void MapControlsToModel(SearchModel model) {
    model.Query = Querybox.Text;
}

It’s now possible to call this method in the Page_Load method to map the controls to the model.

LinqBasedPageExample_1.aspx.cs

protected void Page_Load(object sender, EventArgs e) {
    SearchModel searchModel = new SearchModel();
    if (Page.IsPostBack) {
        MapControlsToModel(searchModel);
    }
}

The controls don’t have values when you first load the page, so it’s not necessary to call them outside of the PostBack.

Query Executer

When executing a query, you need an object that contains all the information you want to retrieve.

To contain the query fields, create a simple SearchResult class.

LinqBasedPageExample_1.aspx.cs

public class SearchResult {
    public DateTime Date { get; set; }
    public string Title { get; set; }
    public string PrintableURI { get; set; }
}

Feel free to add or remove fields to your liking.

Then, create a method called Render containing all your rendering logic.

LinqBasedPageExample_1.aspx.cs

protected void Page_Load(object sender, EventArgs e) {
    SearchModel searchModel = new SearchModel();
    if (Page.IsPostBack) {
        MapControlsToModel(searchModel);
        Render(searchModel);
    }
}


private void Render(SearchModel model) {
    if(!String.IsNullOrEmpty(model.Query)) {
        QueryResults<SearchResult> results = ExecuteQuery(model);
        // Do something with the results
    }
}
  
private QueryResults<SearchResult> ExecuteQuery(SearchModel model) {
    QueryResults<SearchResult> results;
    ISearchIndex index = ContentSearchManager.GetIndex("Coveo_web_index");
    using (var context = index.CreateSearchContext()) {
          IQueryable<SearchResult> query = context.GetQueryable<SearchResult>()
                                                  .CoveoOr(model.Query);
          results = query.GetCoveoQueryResults();
    }
    return results;
}

Query Results Rendering

The following tag contains the search query results when the query has finished executing.

This could be added after the search section; however, you can put it anywhere on your page.

The AutoGenerateColumns="true" attribute specifies that the columns are to be generated based on the object. In the tutorial, each property of the SearchResult class is shown with its name and value.

LinqBasedPageExample_1.aspx

<div ID="ResultsSection" class="resultsSection" runat="server">
    <asp:GridView ID="LSTResults" AutoGenerateColumns="true" runat="server" />
</div>

It’s now possible to bind the query results to the repeater.

The Render method has been split in many sub-methods to clean the code and ease modularity through this tutorial.

  • The ClearResults method clears the results on the page, ensuring there are no leftover results after a new query.
  • The RenderWithResults method is only called when the query has results.
  • The RenderWithoutResults method is only called when there are no results, and serves as feedback for the user when the entered query didn’t match any item.
  • The RenderCommon method is called after each query.

Most of the tutorials add code in one or more of these methods to render the correct information after a query. We recommend that you add your own code in these methods instead of using the Render method if needed.

LinqBasedPageExample_1.aspx.cs

private void Render(SearchModel model) {
    if(!String.IsNullOrEmpty(model.Query)) {
        ClearResults();
        QueryResults<SearchResult> results = ExecuteQuery(model);
        if (results.TotalCount != 0) {
            RenderWithResults(model, results);
        } else {
            RenderWithoutResults(model, results);
        }
        RenderCommon(model, results);
    }
}
  
private void ClearResults() {
    LSTResults.DataSource = "";
    LSTResults.DataBind();
}
  
private void RenderWithResults(SearchModel model,
                               QueryResults<SearchResult> results) {
    LSTResults.DataSource = results.Results;
    LSTResults.DataBind();
}
  
private void RenderWithoutResults(SearchModel model,
                                  QueryResults<SearchResult> results) {
    // No results handling.
}
  
private void RenderCommon(SearchModel model,
                          QueryResults<SearchResult> results) {
    // Rendering with or without results.
}

Result

The search page is now queryable, and should look similar to the following screenshot.

Client-Side Code

The client-side code should now look like this:

LinqBasedPageExample_1.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="LinqBasedPageExample.aspx.cs" Inherits="Tutorial.LinqBasedPageExample" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>LINQ-based Page Example</title>
</head>
<body>
    <form id="pageForm" runat="server">
        <div class="searchSection">
            <asp:Literal Text="Query: " runat="server" />
            <asp:TextBox ID="Querybox" runat="server" />
            <asp:Button type="submit" Text="Run Query" runat="server" />
        </div>
        <div ID="ResultsSection" class="resultsSection" runat="server">
            <asp:GridView ID="LSTResults" AutoGenerateColumns="true" runat="server" />
        </div>
    </form>
</body>
</html>

Server-Side Code

The server-side code should now look like this:

LinqBasedPageExample_1.aspx.cs

namespace Tutorial {
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using Coveo.Framework.SearchService;
    using Coveo.SearchProvider.Linq;
    using Coveo.SearchProvider.LinqBase;
    using Sitecore.ContentSearch;
    using Sitecore.ContentSearch.Linq;
    using Sitecore.ContentSearch.SearchTypes;
    public partial class LinqBasedPageExample : Page {
        protected void Page_Load(object sender, EventArgs e) {
            SearchModel searchModel = new SearchModel();
            if (Page.IsPostBack) {
                MapControlsToModel(searchModel);
                Render(searchModel);
            }
        }
        private void Render(SearchModel model) {
            if (!String.IsNullOrEmpty(model.Query)) {
                ClearResults();
                QueryResults<SearchResult> results = ExecuteQuery(model);
                if (results.TotalCount != 0) {
                    RenderWithResults(model, results);
                } else {
                    RenderWithoutResults(model, results);
                }
                RenderCommon(model, results);
            }
        }
        private void ClearResults() {
            LSTResults.DataSource = "";
            LSTResults.DataBind();
        }
        private void RenderWithResults(SearchModel model,
                                       QueryResults<SearchResult> results) {
            LSTResults.DataSource = results.Results;
            LSTResults.DataBind();
        }
        private void RenderWithoutResults(SearchModel model,
                                          QueryResults<SearchResult> results) {
            // No results handling.
        }
        private void RenderCommon(SearchModel model,
                                  QueryResults<SearchResult> results) {
            // Rendering with or without results.
        }
        private QueryResults<SearchResult> ExecuteQuery(SearchModel model) {
            QueryResults<SearchResult> results;
            ISearchIndex index = ContentSearchManager.GetIndex("Coveo_web_index");
            using (var context = index.CreateSearchContext()) {
                  IQueryable<SearchResult> query = context.GetQueryable<SearchResult>()
                                                          .CoveoOr(model.Query);
                  results = query.GetCoveoQueryResults();
            }
            return results;
        }
        private void MapControlsToModel(SearchModel model) {
            model.Query = Querybox.Text;
        }
    }
    public class SearchModel {
        public string Query { get; set; }
        public SearchModel() {
            Query = "";
        }
    }
    public class SearchResult {
        public DateTime Date { get; set; }
        public string Title { get; set; }
        public string PrintableURI { get; set; }
    }
}