Dela via


Skapa en sökapp i ASP.NET Core

I den här självstudien skapar du en grundläggande ASP.NET Core-app (Model-View-Controller) som körs i localhost och ansluter till hotels-sample-index i söktjänsten. I den här självstudien får du lära dig att:

  • Skapa en grundläggande söksida
  • Filtrera resultat
  • Sortera resultat

Den här självstudien fokuserar på åtgärder på serversidan som anropas via SÖK-API:er. Även om det är vanligt att sortera och filtrera i skript på klientsidan, ger vetskapen om hur du anropar dessa åtgärder på servern fler alternativ när du utformar sökupplevelsen.

Exempelkod för den här självstudien finns på lagringsplatsen azure-search-dotnet-samples på GitHub.

Förutsättningar

Gå igenom guiden Importera data för att skapa hotels-sample-index i söktjänsten. Eller ändra indexnamnet i HomeController.cs filen.

Skapa projektet

  1. Starta Visual Studio och välj Skapa ett nytt projekt.

  2. Välj ASP.NET Core Web App (Model-View-Controller) och välj sedan Nästa.

  3. Ange ett projektnamn och välj sedan Nästa.

  4. På nästa sida väljer du .NET 6.0 eller .NET 7.0 eller .NET 8.0.

  5. Kontrollera att Använd inte toppnivåinstruktioner är avmarkerat.

  6. Välj Skapa.

Lägga till NuGet-paket

  1. I Verktyg väljer du NuGet Package Manager>Hantera NuGet-paket för lösningen.

  2. Azure.Search.Documents Bläddra efter och installera den senaste stabila versionen.

  3. Bläddra efter och installera Microsoft.Spatial paketet. Exempelindexet innehåller en GeographyPoint-datatyp. Om du installerar det här paketet undviks körningsfel. Du kan också ta bort fältet "Plats" från klassen Hotell om du inte vill installera paketet. Det fältet används inte i den här självstudien.

Lägg till tjänstinformation

För anslutningen presenterar appen en fråge-API-nyckel till din fullständigt kvalificerade sök-URL. Båda anges i appsettings.json filen.

Ändra appsettings.json för att ange söktjänsten och fråga EFTER API-nyckeln.

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

Du kan hämta tjänstens URL och API-nyckel från Azure Portal. Eftersom den här koden kör frågor mot ett index och inte skapar en, kan du använda en frågenyckel i stället för en administratörsnyckel.

Se till att ange söktjänsten som har hotels-sample-index.

Lägg till modeller

I det här steget skapar du modeller som representerar schemat för hotels-sample-index.

  1. I Solution Explorer högerklickar du på Modeller och lägger till en ny klass med namnet "Hotel" för följande kod:

     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. Lägg till en klass med namnet "Adress" och ersätt den med följande kod:

     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. Lägg till en klass med namnet "Rooms" och ersätt den med följande kod:

     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. Lägg till en klass med namnet "SearchData" och ersätt den med följande kod:

     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;
         }
     }
    

Ändra kontrollanten

I den här självstudien ändrar du standardvärdet HomeController så att det innehåller metoder som körs i söktjänsten.

  1. Öppna i Solution Explorer under ModellerHomeController.

  2. Ersätt standardvärdet med följande innehåll:

    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();
             }
         }
     }
    

Ändra vyn

  1. Öppna i Solution Explorer under Views Home (Vyer>hem) .index.cshtml

  2. Ersätt standardvärdet med följande innehåll:

    @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>
    

Kör exemplet

  1. Tryck på F5 för att kompilera och köra projektet. Appen körs på den lokala värden och öppnas i standardwebbläsaren.

  2. Välj Sök för att returnera alla resultat.

  3. Den här koden använder standardkonfigurationen för sökning med stöd för den enkla syntaxen och searchMode=Any. Du kan ange nyckelord, utöka med booleska operatorer eller köra en prefixsökning (pool*).

I nästa avsnitt ändrar du metoden RunQueryAsync i HomeController för att lägga till filter och sortering.

Filtrera resultat

Indexfältattribut avgör vilka fält som är sökbara, filterbara, sorterbara, fasettbara och hämtningsbara. I fälten hotels-sample-index innehåller filterbara fält kategori, adress/ort och adress/stateprovince. Det här exemplet lägger till ett $Filter uttryck i Kategori.

Ett filter körs alltid först, följt av en fråga som förutsätter att ett har angetts.

  1. HomeController Öppna och leta upp metoden RunQueryAsync. Lägg till filter i var 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. Kör programmet.

  3. Välj Sök för att köra en tom fråga. Filtret returnerar 18 dokument i stället för de ursprungliga 50.

Mer information om filteruttryck finns i Filter i Azure AI Search och OData $filter syntax i Azure AI Search.

Sortera resultat

I fälten hotels-sample-index inkluderar sorterbara fält Klassificering och LastRenovated. Det här exemplet lägger till ett $OrderBy uttryck i fältet Klassificering.

  1. HomeController Öppna och ersätt Metoden RunQueryAsync med följande version:

     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. Kör programmet. Resultaten sorteras efter Klassificering i fallande ordning.

Mer information om sortering finns i OData $orderby syntax i Azure AI Search.

Nästa steg

I den här självstudien skapade du ett ASP.NET Core-projekt (MVC) som anslöt till en söktjänst och kallade Sök-API:er för filtrering och sortering på serversidan.

Om du vill utforska kod på klientsidan som svarar på användaråtgärder kan du överväga att lägga till en React-mall i din lösning: