Share via


Een zoek-app maken in ASP.NET Core

In deze zelfstudie maakt u een eenvoudige ASP.NET Core-app (Model-View-Controller) die wordt uitgevoerd in localhost en verbinding maakt met de hotels-sample-index in uw zoekservice. In deze zelfstudie leert u het volgende:

  • Een eenvoudige zoekpagina maken
  • Resultaten filteren
  • Resultaten sorteren

In deze zelfstudie wordt de focus gelegd op bewerkingen aan de serverzijde die worden aangeroepen via de zoek-API's. Hoewel het gebruikelijk is om te sorteren en filteren in script aan de clientzijde, krijgt u meer opties bij het ontwerpen van de zoekervaring als u weet hoe u deze bewerkingen op de server kunt aanroepen.

Voorbeeldcode voor deze zelfstudie vindt u in de opslagplaats azure-search-dotnet-samples op GitHub.

Vereisten

Doorloop de wizard Gegevens importeren om de hotels-sample-index in uw zoekservice te maken. Of wijzig de indexnaam in het HomeController.cs bestand.

Het project maken

  1. Start Visual Studio en selecteer Een nieuw project maken.

  2. Selecteer ASP.NET Core Web App (Model-View-Controller) en selecteer vervolgens Volgende.

  3. Geef een projectnaam op en selecteer Vervolgens.

  4. Selecteer op de volgende pagina .NET 6.0 of .NET 7.0 of .NET 8.0.

  5. Controleer of geen instructies op het hoogste niveau worden gebruikt.

  6. Selecteer Maken.

NuGet-pakketten toevoegen

  1. Selecteer NuGet Pakketbeheer> Manage NuGet-pakketten voor de oplossing in Hulpprogramma's.

  2. Azure.Search.Documents Blader naar en installeer de nieuwste stabiele versie.

  3. Blader naar het pakket en installeer het Microsoft.Spatial . De voorbeeldindex bevat een gegevenstype GeographyPoint. Als u dit pakket installeert, worden runtimefouten voorkomen. U kunt ook het veld Locatie uit de klasse Hotels verwijderen als u het pakket niet wilt installeren. Dit veld wordt niet gebruikt in deze zelfstudie.

Servicegegevens toevoegen

Voor de verbinding geeft de app een query-API-sleutel weer voor uw volledig gekwalificeerde zoek-URL. Beide worden opgegeven in het appsettings.json bestand.

Wijzig appsettings.json deze om uw zoekservice en query-API-sleutel op te geven.

{
    "SearchServiceUri": "<YOUR-SEARCH-SERVICE-URL>",
    "SearchServiceQueryApiKey": "<YOUR-SEARCH-SERVICE-QUERY-API-KEY>"
}

U kunt de service-URL en API-sleutel ophalen vanuit de portal. Omdat met deze code een query wordt uitgevoerd op een index en er geen wordt gemaakt, kunt u een querysleutel gebruiken in plaats van een beheersleutel.

Zorg ervoor dat u de zoekservice opgeeft die de hotels-sample-index bevat.

Modellen toevoegen

In deze stap maakt u modellen die het schema van de hotels-sample-index vertegenwoordigen.

  1. Selecteer in Solution Explorer met de rechtermuisknop modellen en voeg een nieuwe klasse met de naam 'Hotel' toe voor de volgende code:

     using Azure.Search.Documents.Indexes.Models;
     using Azure.Search.Documents.Indexes;
     using Microsoft.Spatial;
     using System.Text.Json.Serialization;
    
     namespace HotelDemoApp.Models
     {
         public partial class Hotel
         {
             [SimpleField(IsFilterable = true, IsKey = true)]
             public string HotelId { get; set; }
    
             [SearchableField(IsSortable = true)]
             public string HotelName { get; set; }
    
             [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)]
             public string Description { get; set; }
    
             [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.FrLucene)]
             [JsonPropertyName("Description_fr")]
             public string DescriptionFr { get; set; }
    
             [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
             public string Category { get; set; }
    
             [SearchableField(IsFilterable = true, IsFacetable = true)]
             public string[] Tags { get; set; }
    
             [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
             public bool? ParkingIncluded { get; set; }
    
             [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
             public DateTimeOffset? LastRenovationDate { get; set; }
    
             [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
             public double? Rating { get; set; }
    
             public Address Address { get; set; }
    
             [SimpleField(IsFilterable = true, IsSortable = true)]
             public GeographyPoint Location { get; set; }
    
             public Rooms[] Rooms { get; set; }
         }
     }
    
  2. Voeg een klasse met de naam Adres toe en vervang deze door de volgende code:

     using Azure.Search.Documents.Indexes;
    
     namespace HotelDemoApp.Models
     {
         public partial class Address
         {
             [SearchableField]
             public string StreetAddress { get; set; }
    
             [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
             public string City { get; set; }
    
             [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
             public string StateProvince { get; set; }
    
             [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
             public string PostalCode { get; set; }
    
             [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
             public string Country { get; set; }
         }
     }
    
  3. Voeg een klasse toe met de naam 'Ruimten' en vervang deze door de volgende code:

     using Azure.Search.Documents.Indexes.Models;
     using Azure.Search.Documents.Indexes;
     using System.Text.Json.Serialization;
    
     namespace HotelDemoApp.Models
     {
         public partial class Rooms
         {
             [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnMicrosoft)]
             public string Description { get; set; }
    
             [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.FrMicrosoft)]
             [JsonPropertyName("Description_fr")]
             public string DescriptionFr { get; set; }
    
             [SearchableField(IsFilterable = true, IsFacetable = true)]
             public string Type { get; set; }
    
             [SimpleField(IsFilterable = true, IsFacetable = true)]
             public double? BaseRate { get; set; }
    
             [SearchableField(IsFilterable = true, IsFacetable = true)]
             public string BedOptions { get; set; }
    
             [SimpleField(IsFilterable = true, IsFacetable = true)]
             public int SleepsCount { get; set; }
    
             [SimpleField(IsFilterable = true, IsFacetable = true)]
             public bool? SmokingAllowed { get; set; }
    
             [SearchableField(IsFilterable = true, IsFacetable = true)]
             public string[] Tags { get; set; }
         }
     }
    
  4. Voeg een klasse met de naam SearchData toe en vervang deze door de volgende code:

     using Azure.Search.Documents.Models;
    
     namespace HotelDemoApp.Models
     {
         public class SearchData
         {
             // The text to search for.
             public string searchText { get; set; }
    
             // The list of results.
             public SearchResults<Hotel> resultList;
         }
     }
    

De controller wijzigen

Voor deze zelfstudie wijzigt u de standaardwaarde HomeController voor methoden die worden uitgevoerd op uw zoekservice.

  1. Open in Solution Explorer onder ModellenHomeController.

  2. Vervang de standaardwaarde door de volgende inhoud:

    using Azure;
     using Azure.Search.Documents;
     using Azure.Search.Documents.Indexes;
     using HotelDemoApp.Models;
     using Microsoft.AspNetCore.Mvc;
     using System.Diagnostics;
    
     namespace HotelDemoApp.Controllers
     {
         public class HomeController : Controller
         {
             public IActionResult Index()
             {
                 return View();
             }
    
             [HttpPost]
             public async Task<ActionResult> Index(SearchData model)
             {
                 try
                 {
                     // Check for a search string
                     if (model.searchText == null)
                     {
                         model.searchText = "";
                     }
    
                     // Send the query to Search.
                     await RunQueryAsync(model);
                 }
    
                 catch
                 {
                     return View("Error", new ErrorViewModel { RequestId = "1" });
                 }
                 return View(model);
             }
    
             [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
             public IActionResult Error()
             {
                 return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
             }
    
             private static SearchClient _searchClient;
             private static SearchIndexClient _indexClient;
             private static IConfigurationBuilder _builder;
             private static IConfigurationRoot _configuration;
    
             private void InitSearch()
             {
                 // Create a configuration using appsettings.json
                 _builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
                 _configuration = _builder.Build();
    
                 // Read the values from appsettings.json
                 string searchServiceUri = _configuration["SearchServiceUri"];
                 string queryApiKey = _configuration["SearchServiceQueryApiKey"];
    
                 // Create a service and index client.
                 _indexClient = new SearchIndexClient(new Uri(searchServiceUri), new AzureKeyCredential(queryApiKey));
                 _searchClient = _indexClient.GetSearchClient("hotels-sample-index");
             }
    
             private async Task<ActionResult> RunQueryAsync(SearchData model)
             {
                 InitSearch();
    
                 var options = new SearchOptions()
                 {
                     IncludeTotalCount = true
                 };
    
                 // Enter Hotel property names to specify which fields are returned.
                 // If Select is empty, all "retrievable" fields are returned.
                 options.Select.Add("HotelName");
                 options.Select.Add("Category");
                 options.Select.Add("Rating");
                 options.Select.Add("Tags");
                 options.Select.Add("Address/City");
                 options.Select.Add("Address/StateProvince");
                 options.Select.Add("Description");
    
                 // For efficiency, the search call should be asynchronous, so use SearchAsync rather than Search.
                 model.resultList = await _searchClient.SearchAsync<Hotel>(model.searchText, options).ConfigureAwait(false);
    
                 // Display the results.
                 return View("Index", model);
             }
             public IActionResult Privacy()
             {
                 return View();
             }
         }
     }
    

De weergave wijzigen

  1. Open in Solution Explorer onder Weergaven>start.index.cshtml

  2. Vervang de standaardwaarde door de volgende inhoud:

    @model HotelDemoApp.Models.SearchData;
    
    @{
        ViewData["Title"] = "Index";
    }
    
    <div>
        <h2>Search for Hotels</h2>
    
        <p>Use this demo app to test server-side sorting and filtering. Modify the RunQueryAsync method to change the operation. The app uses the default search configuration (simple search syntax, with searchMode=Any).</p>
    
        <form asp-controller="Home" asp-action="Index">
            <p>
                <input type="text" name="searchText" />
                <input type="submit" value="Search" />
            </p>
        </form>
    </div>
    
    <div>
        @using (Html.BeginForm("Index", "Home", FormMethod.Post))
        {
            @if (Model != null)
            {
                // Show the result count.
                <p>@Model.resultList.TotalCount Results</p>
    
                // Get search results.
                var results = Model.resultList.GetResults().ToList();
    
                {
                    <table class="table">
                        <thead>
                            <tr>
                                <th>Name</th>
                                <th>Category</th>
                                <th>Rating</th>
                                <th>Tags</th>
                                <th>City</th>
                                <th>State</th>
                                <th>Description</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach (var d in results)
                            {
                                <tr>
                                    <td>@d.Document.HotelName</td>
                                    <td>@d.Document.Category</td>
                                    <td>@d.Document.Rating</td>
                                    <td>@d.Document.Tags[0]</td>
                                    <td>@d.Document.Address.City</td>
                                    <td>@d.Document.Address.StateProvince</td>
                                    <td>@d.Document.Description</td>
                                </tr>
                            }
                        </tbody>
                      </table>
                }
            }
        }
    </div>
    

De voorbeeldtoepassing uitvoeren

  1. Druk op F5 om het project te compileren en uit te voeren. De app wordt uitgevoerd op de lokale host en wordt geopend in uw standaardbrowser.

  2. Selecteer Zoeken om alle resultaten te retourneren.

  3. Deze code maakt gebruik van de standaardzoekconfiguratie, die ondersteuning biedt voor de eenvoudige syntaxis en searchMode=Any. U kunt trefwoorden invoeren, uitbreiden met Booleaanse operatoren of een voorvoegselzoekopdracht (pool*) uitvoeren.

Wijzig in de volgende secties de methode RunQueryAsync in de HomeController methode om filters en sortering toe te voegen.

Resultaten filteren

Indexveldkenmerken bepalen welke velden doorzoekbaar, filterbaar, sorteerbaar, facetable en ophaalbaar zijn. In de hotels-sample-index bevatten filterbare velden Categorie, Adres/Plaats en Adres/StateProvince. In dit voorbeeld wordt een $Filter expressie toegevoegd aan Categorie.

Een filter wordt altijd eerst uitgevoerd, gevolgd door een query, ervan uitgaande dat er een is opgegeven.

  1. Open de HomeController methode RunQueryAsync en zoek deze. Filter toevoegen aanvar options = new SearchOptions():

     private async Task<ActionResult> RunQueryAsync(SearchData model)
     {
         InitSearch();
    
         var options = new SearchOptions()
         {
             IncludeTotalCount = true,
             Filter = "search.in(Category,'Budget,Suite')"
         };
    
         options.Select.Add("HotelName");
         options.Select.Add("Category");
         options.Select.Add("Rating");
         options.Select.Add("Tags");
         options.Select.Add("Address/City");
         options.Select.Add("Address/StateProvince");
         options.Select.Add("Description");
    
         model.resultList = await _searchClient.SearchAsync<Hotel>(model.searchText, options).ConfigureAwait(false);
    
         return View("Index", model);
     }
    
  2. Voer de toepassing uit.

  3. Selecteer Zoeken om een lege query uit te voeren. Het filter retourneert 18 documenten in plaats van de oorspronkelijke 50.

Zie Filters in Azure AI Search en OData $filter syntaxis in Azure AI Search voor meer informatie over filterexpressies.

Resultaten sorteren

In de hotels-sample-index zijn sorteerbare velden rating en LastRenovated. In dit voorbeeld wordt een $OrderBy-expressie toegevoegd aan het veld Waardering.

  1. Open de HomeController methode RunQueryAsync en vervang deze door de volgende versie:

     private async Task<ActionResult> RunQueryAsync(SearchData model)
     {
         InitSearch();
    
         var options = new SearchOptions()
         {
             IncludeTotalCount = true,
         };
    
         options.OrderBy.Add("Rating desc");
    
         options.Select.Add("HotelName");
         options.Select.Add("Category");
         options.Select.Add("Rating");
         options.Select.Add("Tags");
         options.Select.Add("Address/City");
         options.Select.Add("Address/StateProvince");
         options.Select.Add("Description");
    
         model.resultList = await _searchClient.SearchAsync<Hotel>(model.searchText, options).ConfigureAwait(false);
    
         return View("Index", model);
     }
    
  2. Voer de toepassing uit. Resultaten worden gesorteerd op Classificatie in aflopende volgorde.

Zie OData $orderby syntaxis in Azure AI Search voor meer informatie over sorteren.

Volgende stappen

In deze zelfstudie hebt u een ASP.NET Core-project (MVC) gemaakt dat is verbonden met een zoekservice en zoek-API's genoemd voor filteren en sorteren op de server.

Als u code aan de clientzijde wilt verkennen die reageert op gebruikersacties, kunt u een React-sjabloon toevoegen aan uw oplossing: