Keresési alkalmazás létrehozása a ASP.NET Core-ban

Ebben az oktatóanyagban hozzon létre egy alapszintű ASP.NET Core (Model-View-Controller) alkalmazást, amely a localhostban fut, és csatlakozik a keresési szolgáltatás hotels-sample-indexéhez. Az oktatóanyag segítségével megtanulhatja a következőket:

  • Alapszintű keresési oldal létrehozása
  • Szűrés eredményei
  • Az eredmények rendezése

Ez az oktatóanyag a keresési API-kon keresztül meghívott kiszolgálóoldali műveletekre helyezi a hangsúlyt. Bár az ügyféloldali szkriptekben gyakran történik rendezés és szűrés, a keresési felület tervezésekor több lehetőséget is kínál a műveletek kiszolgálóra való meghívása.

Az oktatóanyag mintakódja a GitHub azure-search-dotnet-samples adattárában található.

Előfeltételek

Az Adatok importálása varázslóval létrehozhatja a hotels-sample-indexet a keresési szolgáltatásban. Vagy módosítsa az index nevét a HomeController.cs fájlban.

A projekt létrehozása

  1. Indítsa el a Visual Studiót, és válassza az Új projekt létrehozása lehetőséget.

  2. Válassza ASP.NET Core Web App (Model-View-Controller) lehetőséget, majd válassza a Tovább gombot.

  3. Adjon meg egy projektnevet, majd válassza a Tovább gombot.

  4. A következő lapon válassza a .NET 6.0 vagy a .NET 7.0 vagy a .NET 8.0 lehetőséget.

  5. Ellenőrizze, hogy nincs-e bejelölve a felső szintű utasítások használata.

  6. Válassza a Létrehozás lehetőséget.

NuGet-csomagok hozzáadása

  1. Az Eszközök lapon válassza a MegoldásHoz tartozó NuGet-Csomagkezelő> Manage NuGet-csomagokat.

  2. Keresse meg Azure.Search.Documents és telepítse a legújabb stabil verziót.

  3. Keresse meg és telepítse a Microsoft.Spatial csomagot. A mintaindex tartalmaz egy GeographyPoint-adattípust. A csomag telepítése elkerüli a futásidejű hibákat. Ha nem szeretné telepíteni a csomagot, távolítsa el a "Hely" mezőt a Hotels osztályból. Ez a mező nem használatos ebben az oktatóanyagban.

Szolgáltatásadatok hozzáadása

A kapcsolathoz az alkalmazás egy lekérdezési API-kulcsot jelenít meg a teljes keresési URL-címhez. Mindkettő meg van adva a appsettings.json fájlban.

Módosítsa appsettings.json a keresési szolgáltatás és a lekérdezési API-kulcs megadásához.

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

A szolgáltatás URL-címét és API-kulcsát a portálról szerezheti be. Mivel ez a kód egy indexet kérdez le, és nem hoz létre egyet, rendszergazdai kulcs helyett lekérdezési kulcsot is használhat.

Mindenképpen adja meg azt a keresési szolgáltatást, amely a hotels-sample-indexet tartalmazza.

Modellek hozzáadása

Ebben a lépésben olyan modelleket hozhat létre, amelyek a hotels-sample-index sémáját képviselik.

  1. A Megoldáskezelőben válassza a jobb gombbal a Modellek lehetőséget, és adjon hozzá egy "Hotel" nevű új osztályt a következő kódhoz:

     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. Adjon hozzá egy "Address" nevű osztályt, és cserélje le a következő kódra:

     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. Adjon hozzá egy "Szobák" nevű osztályt, és cserélje le a következő kódra:

     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. Adjon hozzá egy "SearchData" nevű osztályt, és cserélje le a következő kódra:

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

A vezérlő módosítása

Ebben az oktatóanyagban módosítsa az alapértelmezett HomeController beállítást úgy, hogy a keresési szolgáltatáson végrehajtott metódusokat tartalmazza.

  1. A Megoldáskezelő Modellek csoportjában nyissa meg a elemetHomeController.

  2. Cserélje le az alapértelmezett értéket a következő tartalomra:

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

A nézet módosítása

  1. Nyissa meg index.cshtmla Megoldáskezelőben a Nézetek>kezdőlapja alatt.

  2. Cserélje le az alapértelmezett értéket a következő tartalomra:

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

Minta futtatása

  1. A projekt fordításához és futtatásához nyomja le az F5 billentyűt. Az alkalmazás helyi gazdagépen fut, és az alapértelmezett böngészőben nyílik meg.

  2. Válassza a Keresés lehetőséget az összes találat visszaadásához.

  3. Ez a kód az alapértelmezett keresési konfigurációt használja, amely támogatja az egyszerű szintaxist és searchMode=Anya . Megadhat kulcsszavakat, bővíthet logikai operátorokkal, vagy futtathat előtagkeresést (pool*).

A következő szakaszokban módosítsa a RunQueryAsync metódust a HomeController szűrők és rendezés hozzáadásához.

Szűrés eredményei

Az indexmező attribútumai határozzák meg, hogy mely mezők kereshetők, szűrhetők, rendezhetők, táblázatosak és lekérdezhetők. A szállodák mintaindexében a szűrhető mezők közé tartozik a Kategória, a Cím/Város és a Cím/StateProvince. Ez a példa egy $Filter kifejezést ad hozzá a Kategóriához.

A szűrő mindig először fut, majd egy lekérdezés, feltéve, hogy van megadva.

  1. Nyissa meg a HomeController RunQueryAsync metódust, és keresse meg. Szűrő hozzáadása a következőhözvar 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. Futtassa az alkalmazást.

  3. Üres lekérdezés futtatásához válassza a Keresés lehetőséget. A szűrő az eredeti 50 helyett 18 dokumentumot ad vissza.

További információ a szűrőkifejezésekről: Szűrők az Azure AI Searchben és OData $filter szintaxis az Azure AI Searchben.

Az eredmények rendezése

A szállodák mintaindexében a rendezhető mezők közé tartozik a Minősítés és a LastRenovated. Ez a példa egy $OrderBy kifejezést ad hozzá a Minősítés mezőhöz.

  1. Nyissa meg és cserélje le a HomeController RunQueryAsync metódust a következő verzióra:

     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. Futtassa az alkalmazást. Az eredmények besorolása csökkenő sorrendben van rendezve.

A rendezéssel kapcsolatos további információkért lásd az OData $orderby szintaxisát az Azure AI Searchben.

Következő lépések

Ebben az oktatóanyagban létrehozott egy ASP.NET Core (MVC) projektet, amely egy keresési szolgáltatáshoz csatlakozott, és a kiszolgálóoldali szűréshez és rendezéshez keresési API-knak nevezett.

Ha meg szeretné vizsgálni a felhasználói műveletekre reagáló ügyféloldali kódot, fontolja meg egy React-sablon hozzáadását a megoldáshoz: