Eine Such-App in ASP.NET Core erstellen
Erstellen Sie in diesem Tutorial eine einfache ASP.NET Core-App (Model View Controller), die im Localhost ausgeführt wird und eine Verbindung mit dem Hotelbeispielindex in Ihrem Suchdienst herstellt. In diesem Tutorial lernen Sie Folgendes:
- Eine einfache Suchseite erstellen
- Ergebnisse filtern
- Ergebnisse sortieren
In diesem Tutorial liegt der Fokus auf serverseitigen Vorgängen, die über die Such-APIs aufgerufen werden. Obwohl es üblich ist, in clientseitigen Skripts zu sortieren und zu filtern, gibt Ihnen das Wissen, wie diese Vorgänge auf dem Server aufgerufen werden, mehr Möglichkeiten beim Entwerfen der Suchumgebung.
Den Beispielcode für dieses Tutorial finden Sie im Repository azure-search-dotnet-samples auf GitHub.
Voraussetzungen
- Visual Studio
- NuGet-Paket „Azure.Search.Documents“
- Azure KI-Suche (beliebige Ebene) muss über Zugriff auf das öffentliche Netzwerk verfügen.
- Index der Hotelstichproben
Durchlaufen Sie den Assistenten zum Importieren von Daten, um den Index für Hotelstichproben für Ihren Suchdienst zu erstellen. Oder ändern Sie den Indexnamen in der Datei HomeController.cs
.
Erstellen des Projekts
Starten Sie Visual Studio, und wählen Sie Neues Projekt erstellen aus.
Wählen Sie ASP.NET Core Web-App (Model View Controller) und dann Weiter aus.
Geben Sie einen Projektnamen an, und wählen Sie dann Weiter aus.
Wählen Sie auf der nächsten Seite .NET 6.0, .NET 7.0 oder .NET 8.0 aus.
Vergewissern Sie sich, dass Keine Anweisungen der obersten Ebene verwenden nicht aktiviert ist.
Klicken Sie auf Erstellen.
Hinzufügen von NuGet-Paketen
Wählen Sie unter Tools die Option NuGet-Paket-Manager>NuGet-Pakete für die Lösung verwalten aus.
Suchen Sie nach dem Paket
Azure.Search.Documents
, und installieren Sie die neuste stabile Version.Suchen Sie nach dem Paket
Microsoft.Spatial
, und installieren Sie es. Der Beispielindex enthält den Datentyp „GeographyPoint“. Durch die Installation dieses Pakets werden Laufzeitfehler vermieden. Alternativ können Sie das Feld „Standort“ aus der Hotelklasse entfernen, wenn Sie das Paket nicht installieren möchten. Dieses Feld wird in diesem Tutorial nicht verwendet.
Dienstinformationen hinzufügen
Für die Verbindung stellt die App Ihrer vollqualifizierten Such-URL einen Abfrage-API-Schlüssel vor. Beide werden in der Datei appsettings.json
angegeben.
Ändern Sie appsettings.json
, um Ihren Suchdienst und Abfrage-API-Schlüssel anzugeben.
{
"SearchServiceUri": "<YOUR-SEARCH-SERVICE-URL>",
"SearchServiceQueryApiKey": "<YOUR-SEARCH-SERVICE-QUERY-API-KEY>"
}
Sie können die Dienst-URL und den API-Schlüssel aus dem Portal abrufen. Da dieser Code einen Index abfragt und keinen erstellt, können Sie einen Abfrageschlüssel anstelle eines Administratorschlüssels verwenden.
Stellen Sie sicher, dass Sie den Suchdienst angeben, der über den hotels-sample-index verfügt.
Modelle hinzufügen
Erstellen Sie in diesem Schritt Modelle, die das Schema des hotels-sample-index darstellen.
Wählen Sie im Projektmappen-Explorer mit der rechten Maustaste Modelle aus, und fügen Sie eine neue Klasse namens „Hotel“ für den folgenden Code hinzu:
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; } } }
Fügen Sie eine Klasse namens „Adresse“ hinzu, und ersetzen Sie sie durch den folgenden 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; } } }
Fügen Sie eine Klasse namens „Räume“ hinzu, und ersetzen Sie sie durch den folgenden 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; } } }
Fügen Sie eine Klasse namens „DatenDurchsuchen“ hinzu, und ersetzen Sie sie durch den folgenden 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; } }
Controller ändern
Ändern Sie in diesem Tutorial den Standardwert HomeController
so, dass Methoden enthalten sind, die in Ihrem Suchdienst ausgeführt werden.
Öffnen Sie im Projektmappen-Explorer unter Modelle
HomeController
.Ersetzen Sie den Standardcode durch den folgenden Inhalt:
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(); } } }
Ansicht ändern
Öffnen Sie im Projektmappen-Explorer unter Ansichten>Startseite
index.cshtml
.Ersetzen Sie den Standardcode durch den folgenden Inhalt:
@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>
Ausführen des Beispiels
Drücken Sie F5, um das Projekt zu kompilieren und auszuführen. Die App wird auf dem lokalen Host ausgeführt und in Ihrem Standardbrowser geöffnet.
Wählen Sie Suchen aus, um alle Ergebnisse zurückzugeben.
Dieser Code verwendet die Standardsuchkonfiguration und unterstützt die einfache Syntax und
searchMode=Any
. Sie können Schlüsselwörter eingeben, mit booleschen Operatoren erweitern oder eine Präfixsuche ausführen (pool*
).
Ändern Sie in den nächsten Abschnitten die Methode RunQueryAsync zu HomeController
, um Filter und Sortierung hinzuzufügen.
Ergebnisse filtern
Indexfeldattribute bestimmen, welche Felder durchsuchbar, filterbar, sortierbar, facettierbar und abrufbar sind. Zu dem im Index für Hotelstichproben enthaltenen filterbaren Feldern gehören „Kategorie“, „Adresse/Stadt“ und „Adresse/BundeslandKanton“. In diesem Beispiel wird für „Kategorie“ ein $Filter-Ausdruck hinzugefügt.
Ein Filter wird immer zuerst ausgeführt, gefolgt von einer Abfrage, sofern eine angegeben wurde.
Öffnen Sie
HomeController
, und suchen Sie die Methode RunQueryAsync. Fügen Sie Filter zuvar options = new SearchOptions()
hinzu: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); }
Führen Sie die Anwendung aus.
Klicken Sie auf Suchen, um eine leere Abfrage auszuführen. Mit den Filterkriterien werden anstelle der ursprünglichen 50 Dokumente nur 18 Dokumente zurückgegeben.
Weitere Informationen zu Filterausdrücken finden Sie unter Filter in Azure KI Search und OData-Syntax von „$filter“ in Azur KI Search.
Ergebnisse sortieren
Zu den im Index für Hotelstichproben enthaltenen sortierbaren Feldern gehören „Bewertung“ und „ZuletztRenoviert“. In diesem Beispiel wird dem Feld „Bewertung“ ein $OrderBy-Ausdruck hinzugefügt.
Öffnen Sie die
HomeController
, und ersetzen Sie die Methode RunQueryAsync durch die folgende 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); }
Führen Sie die Anwendung aus. Die Ergebnisse werden nach „Bewertung“ in absteigender Reihenfolge sortiert.
Weitere Informationen zum Sortieren finden Sie unter OData-Syntax von „$orderby“ in Azure KI Search.
Nächste Schritte
In diesem Tutorial haben Sie ein ASP.NET Core (MVC)-Projekt erstellt, das eine Verbindung mit einem Suchdienst hergestellt und Such-APIs für serverseitige Filterung und Sortierung aufgerufen hat.
Wenn Sie clientseitigen Code erkunden möchten, der auf Benutzeraktionen reagiert, sollten Sie ihrer Lösung eine React-Vorlage hinzufügen: