paint-brush
Erstellen Sie mit Twilio und ASP.NET Core einen Quiz-WhatsApp-Botvon@zadok
2,604 Lesungen
2,604 Lesungen

Erstellen Sie mit Twilio und ASP.NET Core einen Quiz-WhatsApp-Bot

von Zadok J.15m2023/09/15
Read on Terminal Reader
Read this story w/o Javascript

Zu lang; Lesen

In dieser Anleitung erfahren Sie, wie Sie mit Twilio für WhatsApp, ASP.NET Core und der Trivia-API ein Trivia-Quiz erstellen.
featured image - Erstellen Sie mit Twilio und ASP.NET Core einen Quiz-WhatsApp-Bot
Zadok J. HackerNoon profile picture
0-item
1-item

Quizspiele bieten ein fesselndes und lehrreiches Erlebnis, bei dem Sie neue Fakten erfahren und Ihr Wissen über verschiedene Themen hinweg erweitern können. Heutzutage sind Trivia-Quiz-Mobil- und Webanwendungen die häufigsten Anlaufstellen für eine solche Aktivität. Wie wäre es mit einem Quizspiel auf WhatsApp?


In diesem Tutorial-Leitfaden erfahren Sie, wie Sie mit Twilio für WhatsApp, ASP.NET Core und eine Trivia-Quizanwendung erstellen Die Trivia-API ( lizenziert unter CC BY-NC 4.0 ). Das Ziel dieses Tutorials besteht darin, eine Quizspielanwendung zu erstellen, mit der Benutzer Multiple-Choice-Fragen mit WhatsApp spielen und beantworten können. Sie werden Nutzen daraus ziehen Sitzungen in ASP.NET Core um den Benutzerfortschritt zu speichern und abzurufen, den Punktestand zu verfolgen und den Spielstatus aufrechtzuerhalten.


Um diese Fragen abzurufen, verwenden Sie die Trivia API, eine REST-API, die es Entwicklern erleichtert, Quiz-Apps zu erstellen, indem sie Multiple-Choice-Trivia-Fragen bereitstellt. Um mehr über die Trivia-API zu erfahren, besuchen Sie bitte die__ Trivia-API-Dokumentation__ .


Voraussetzungen

Um dieses Tutorial abzuschließen, benötigen Sie:


Den Quellcode für dieses Tutorial finden Sie auf GitHub .


Richten Sie ein neues ASP.NET Core-Projekt ein

Führen Sie zunächst über Ihr Shell-Terminal in einem bevorzugten Arbeitsverzeichnis die folgenden Befehle aus, um ein neues Web-API-Projekt zu erstellen:


 dotnet new webapi -n TwilioWhatsAppTriviaApp --no-openapi


Der zweite Befehl im obigen Snippet erstellt ein neues Web-API-Projekt mit dem angegebenen Namen und ohne OpenAPI-Unterstützung (Swagger). Wenn Sie Swagger im Projekt verwenden möchten, lassen Sie im obigen Befehl einfach --no-openapi weg.


Wechseln Sie in das Projektverzeichnis, indem Sie diesen Befehl ausführen:


 cd TwilioWhatsAppTriviaApp


Installiere das Twilio-Hilfsbibliothek für ASP.NET Core NuGet-Paket:


 dotnet add package Twilio.AspNet.Core


Diese Bibliothek vereinfacht die Arbeit mit Twilio-Webhooks und APIs in einer ASP.NET Core-Anwendung.


Öffnen Sie das Projekt mit Ihrer bevorzugten IDE. Entfernen Sie im Ordner „Controllers“ die Boilerplate-Controller-Vorlagendatei „WeatherForecastController.cs “ und entfernen Sie auch „ WeatherForcast.cs“ im Projektverzeichnis.


Erstellen Sie Ihr Projekt und führen Sie es aus, um sicherzustellen, dass alles, was Sie bisher getan haben, ordnungsgemäß funktioniert, indem Sie die folgenden Befehle verwenden:


 dotnet build dotnet run


Notieren Sie sich nach erfolgreicher Ausführung des Projekts alle Localhost-URLs, die in der Debugging-Konsole angezeigt werden. Sie können jede dieser URLs verwenden, um mit ngrok einen öffentlich zugänglichen lokalen Webserver einzurichten.


localhost-URLs


Implementieren Sie Sitzungen

Sitzungen sind eine von mehreren Möglichkeiten, die Daten eines Benutzers in einer ASP.NET Core-Anwendung zu speichern. Dies ist wichtig, wenn Sie Benutzerdaten zwischen Anfragen beibehalten möchten, da das HTTP-Protokoll standardmäßig zustandslos ist – das bedeutet, dass Daten nicht erhalten bleiben.

Fügen Sie den In-Memory-Sitzungsanbieter hinzu, indem Sie Program.cs ändern, wie im folgenden Code gezeigt:


 var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddDistributedMemoryCache(); builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromSeconds(40); options.Cookie.IsEssential = true; }); var app = builder.Build(); app.UseSession(); app.MapControllers(); app.Run();


AddDistributedMemoryCache() registriert den verteilten Speicher-Cache-Dienst. Dieser Dienst stellt einen In-Memory-Cache bereit, der zum Speichern und Abrufen von Daten über mehrere Anfragen oder Sitzungen hinweg verwendet werden kann.


AddSession() registriert die Sitzungsdienste und ermöglicht der Anwendung, den Sitzungsstatus beizubehalten. Mit dem options können Sie verschiedene sitzungsbezogene Optionen konfigurieren. IdleTimeout wird verwendet, um die Dauer der Inaktivität festzulegen, nach der eine Sitzung als inaktiv betrachtet wird. In diesem Fall ist sie auf 40 Sekunden eingestellt. Cookie.IsEssential stellt sicher, dass der Sitzungsstatus auch in Szenarien, in denen die Cookie-Ablehnung aktiviert ist, funktionsfähig bleibt.


Die Sitzungsunterstützung wird durch das Hinzufügen der UseSession Middleware zur Anwendungspipeline aktiviert, d. h. Ihre Anwendung erhält Zugriff auf ein Sitzungsobjekt, das zum Speichern und Abrufen von Daten verwendet werden kann.


Erstellen Sie die Modelle

Erstellen Sie einen neuen Ordner, Models, in Ihrem Projektverzeichnis. Fügen Sie zwei Modellklassendateien hinzu, TriviaApiResponse.cs und Question.cs , mit Eigenschaften, wie in den folgenden Codebeispielen gezeigt:


 using Newtonsoft.Json; namespace TwilioWhatsAppTriviaApp.Models; public class TriviaApiResponse { [JsonProperty("category")] public string Category { get; set; } [JsonProperty("correctAnswer")] public string CorrectAnswer { get; set; } [JsonProperty("incorrectAnswers")] public List<string> IncorrectAnswers { get; set; } [JsonProperty("question")] public string Question { get; set; } [JsonProperty("type")] public string? Type { get; set; } [JsonProperty("difficulty")] public string Difficulty { get; set; } }


 namespace TwilioWhatsAppTriviaApp.Models; public class Question { public string QuestionText { get; set; } public List<(string option, bool isCorrect)> Options { get; set; } }


Das TriviaApiResponse Modell enthält Eigenschaften, die die Felder der Trivia-API-Antwort darstellen. Das JsonProperty Attribut stellt sicher, dass jede Eigenschaft korrekt mit den entsprechenden JSON-Daten gefüllt wird.


Für eine optimierte Bearbeitung trivialer Fragen kommt die Question Klasse zum Einsatz. Diese Klasse kapselt die notwendigen Informationen für eine Trivia-Frage, einschließlich des Fragetextes und einer Liste von Optionen. Jede Option wird durch ein Tupel dargestellt, das den Optionstext und einen booleschen Wert enthält, der angibt, ob es sich um die richtige Option handelt.


Fügen Sie die Trivia-Serviceklasse hinzu

Erstellen Sie einen Services- Ordner in Ihrem Projektverzeichnis und fügen Sie eine neue Klassendatei mit dem Namen TriviaService.cs hinzu. Ändern Sie den Inhalt, wie im folgenden Code gezeigt:


 using Newtonsoft.Json; using TwilioWhatsAppTriviaApp.Models; namespace TwilioWhatsAppTriviaApp.Services; public class TriviaService { private const string TheTriviaApiUrl = @"https://the-trivia-api.com/api/questions?limit=3"; private HttpClient httpClient; public TriviaService(HttpClient httpClient) { this.httpClient = httpClient; } public async Task<IEnumerable<TriviaApiResponse>> GetTrivia() { var response = await httpClient.GetAsync(TheTriviaApiUrl); var triviaJson = await response.Content.ReadAsStringAsync(); var trivia = JsonConvert.DeserializeObject<IEnumerable<TriviaApiResponse>>(triviaJson); return trivia; } public List<Question> ConvertTriviaToQuestions(IEnumerable<TriviaApiResponse> questions) { List<Question> newQuestions = new(); foreach (var question in questions) { var options = new List<(string option, bool isCorrect)>() { (question.CorrectAnswer, true), (question.IncorrectAnswers[0], false), (question.IncorrectAnswers[1], false), (question.IncorrectAnswers[2], false) }; // Shuffle the options randomly Random random = new(); options = options.OrderBy(_ => random.Next()).ToList(); newQuestions.Add(new Question { QuestionText = question.Question, Options = options }); } return newQuestions; } }


Die Klasse TriviaService enthält zwei Methoden: GetTrivia und ConvertTriviaToQuestions . Die GetTrivia Methode sendet die HTTP-GET-Anfrage mit dem Abfrageparameter limit=3 an die Trivia-API, der angibt, dass nur drei Fragen zurückgegeben werden sollen. Ohne den limit-Parameter gibt die API standardmäßig 10 Fragen zurück.


Die ConvertTriviaToQuestions Methode wandelt die Antwort von der API in eine organisierte Form um. Die Methode mischt außerdem alle Frageoptionen nach dem Zufallsprinzip, sodass eine einzelne Option nicht die Antwort auf alle Fragen ist.


Um TriviaService und den HTTP-Client im Dependency Injection (DI)-Container Ihrer Anwendung zu registrieren, ändern Sie Program.cs wie im folgenden Code gezeigt:


 using TwilioWhatsAppTriviaApp.Services; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddDistributedMemoryCache(); builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromSeconds(40); options.Cookie.IsEssential = true; }); builder.Services.AddHttpClient(); builder.Services.AddScoped<TriviaService>(); var app = builder.Build(); app.UseSession(); app.MapControllers(); app.Run();


Erstellen Sie den Trivia-Controller

Fügen Sie eine leere API-Controller-Klasse in einer Datei namens TriviaController.cs zum Ordner „Controllers“ hinzu und ändern Sie deren Inhalt wie im folgenden Code gezeigt:


 using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Twilio.AspNet.Core; using Twilio.TwiML; using Twilio.TwiML.Messaging; using TwilioWhatsAppTriviaApp.Models; using TwilioWhatsAppTriviaApp.Services; namespace WhatsappTrivia.Controllers; [Route("[controller]")] [ApiController] public class TriviaController : TwilioController { private const string SessionKeyIsGameOn = "IsGameOn"; private const string SessionKeyScore = "Score"; private const string SessionKeyCurrentQuestionIndex = "CurrentQuestionIndex"; private const string SessionKeyTotalQuestions = "TotalQuestions"; private const string SessionKeyQuestions = "Questions"; private static readonly string[] StartCommands = { "START", "S" }; private static readonly string[] OptionValues = { "A", "B", "C", "D" }; private readonly TriviaService triviaService; public TriviaController(TriviaService triviaService) { this.triviaService = triviaService; } [HttpPost] public async Task<IActionResult> Index() { var response = new MessagingResponse(); var form = await Request.ReadFormAsync(); var body = form["Body"].ToString().ToUpper().Trim(); await HttpContext.Session.LoadAsync(); var isGameOn = Convert.ToBoolean(HttpContext.Session.GetString(SessionKeyIsGameOn)); int currentQuestionIndex = HttpContext.Session.GetInt32(SessionKeyCurrentQuestionIndex) ?? 0; int totalQuestions = HttpContext.Session.GetInt32(SessionKeyTotalQuestions) ?? 0; if (StartCommands.Contains(body) && !isGameOn) { await StartGame(); HttpContext.Session.SetString(SessionKeyIsGameOn, "true"); response.Message(PresentQuestionWithOptions(currentQuestionIndex)); return TwiML(response); } if (OptionValues.Contains(body) && isGameOn) { var result = ProcessUserAnswer(body, currentQuestionIndex); response.Message(result); currentQuestionIndex++; if (currentQuestionIndex <= totalQuestions - 1) { HttpContext.Session.SetInt32(SessionKeyCurrentQuestionIndex, currentQuestionIndex); response.Append(new Message(PresentQuestionWithOptions(currentQuestionIndex))); } else { response.Append(new Message(EndTrivia())); } return TwiML(response); } response.Message(!isGameOn ? "*Hello! Send 'Start' or 'S' to play game*" : "*Invalid Input! Send a correct option 'A', 'B', 'C' or 'D'*"); return TwiML(response); } private async Task StartGame() { if (HttpContext.Session.GetString(SessionKeyQuestions) != null) { HttpContext.Session.Remove(SessionKeyQuestions); } var trivia = await this.triviaService.GetTrivia(); var questions = this.triviaService.ConvertTriviaToQuestions(trivia); AddNewQuestionsToSession(questions); HttpContext.Session.SetInt32(SessionKeyTotalQuestions, questions.Count); } private string ProcessUserAnswer(string userAnswer, int questionIndex) { bool optionIsCorrect = false; int score = HttpContext.Session.GetInt32(SessionKeyScore) ?? 0; var question = RetrieveQuestionFromSession(questionIndex); switch (userAnswer) { case "A": optionIsCorrect = question.Options[0].isCorrect; break; case "B": optionIsCorrect = question.Options[1].isCorrect; break; case "C": optionIsCorrect = question.Options[2].isCorrect; break; case "D": optionIsCorrect = question.Options[3].isCorrect; break; } if (optionIsCorrect) { score++; HttpContext.Session.SetInt32(SessionKeyScore, score); } return optionIsCorrect ? "_Correct ✅_" : $"_Incorrect ❌ Correct answer is {question.Options.Find(o => o.isCorrect).option.TrimEnd()}_"; } private string PresentQuestionWithOptions(int questionIndex) { var question = RetrieveQuestionFromSession(questionIndex); return $""" {questionIndex + 1}. {question.QuestionText} {OptionValues[0]}. {question.Options[0].option} {OptionValues[1]}. {question.Options[1].option} {OptionValues[2]}. {question.Options[2].option} {OptionValues[3]}. {question.Options[3].option} """; } private void AddNewQuestionsToSession(List<Question> questions) => HttpContext.Session.SetString(SessionKeyQuestions, JsonConvert.SerializeObject(questions)); private Question RetrieveQuestionFromSession(int questionIndex) { var questionsFromSession = HttpContext.Session.GetString(SessionKeyQuestions); return JsonConvert.DeserializeObject<List<Question>>(questionsFromSession)[questionIndex]; } private string EndTrivia() { var score = HttpContext.Session.GetInt32(SessionKeyScore) ?? 0; var totalQuestions = HttpContext.Session.GetInt32(SessionKeyTotalQuestions) ?? 0; var userResult = $""" Thanks for playing! 😊 You answered {score} out of {totalQuestions} questions correctly. To play again, send 'Start' or 'S' """; HttpContext.Session.Clear(); return userResult; } }


Diese Controller-Klasse ist für die Verarbeitung eingehender Nachrichten, die Verwaltung des Sitzungsstatus und die Generierung von Antworten verantwortlich. Es erbt von der TwilioController Klasse, die von der Twilio.AspNet.Core-Bibliothek bereitgestellt wird und Ihnen Zugriff auf die TwiML Methode ermöglicht. Mit dieser Methode können Sie antworten TwiML, die Twilio Markup Language . Die TriviaController Klasse verwendet HttpContext.Session Methoden, um mit der Sitzung zu interagieren.

Die gültigen Eingaben sind Elemente in den schreibgeschützten Arrays StartCommands und OptionValues . Der Text der eingehenden Nachricht wird mit diesen Elementen verglichen, um sicherzustellen, dass der Benutzer eine korrekte Eingabe gesendet hat. Andernfalls wird eine Nachricht an den Benutzer gesendet, die ihn auffordert, basierend auf dem aktuellen Status des Spiels die richtige Eingabe vorzunehmen. Andere Felder mit dem Präfix „SessionKey“ werden verwendet, um private Konstantenzeichenfolgen für Sitzungsschlüssel im Programm zu definieren.


Die Index Methode ist die Hauptaktionsmethode, die eingehende HTTP-POST-Anfragen von WhatsApp über die /Trivia- Route verarbeitet. Es lädt die Sitzungsdaten mit HttpContext.Session.LoadAsync() und ruft mit den Methoden HttpContext.Session.GetString() und HttpContext.Session.GetInt32() Daten zum Spielstatus aus der Sitzung ab.


Durch die Verwendung von Unterstrichen (_) und Sternchen (*) am Anfang und Ende bestimmter Zeichenfolgen wird eine kursive bzw. fette Textformatierung in gerenderten WhatsApp-Nachrichten erreicht.


Jede Hilfsmethode im TriviaController führt eine bestimmte Aufgabe aus, die die Hauptfunktionalität der Klasse unterstützt.

  • StartGame Methode initialisiert das Spiel, indem sie Quizfragen abruft, sie in ein für das Spiel geeignetes Format konvertiert und sie in der Sitzung speichert.
  • ProcessUserAnswer Methode verarbeitet die Antwort des Benutzers auf eine Frage und bestimmt, ob sie richtig ist oder nicht.
  • Die Methode PresentQuestionWithOptions ist für die Formatierung und Darstellung einer Frage zusammen mit ihren Optionen verantwortlich.
  • AddNewQuestionsToSession Methode speichert eine Liste von Fragen in der Sitzung. Es konvertiert die Fragen in das JSON-Format und speichert die JSON-Zeichenfolge in der Sitzung.
  • RetrieveQuestionFromSession Methode ruft mithilfe des Fragenindex eine Frage aus der Sitzung ab.
  • EndTrivia Methode generiert eine Nachricht zum Beenden des Quizspiels. Diese Methode entfernt auch Sitzungsdaten im Zusammenhang mit dem Spiel. Basierend auf der Konfiguration des Sitzungsdiensts in Program.cs geschieht dies automatisch, wenn die Sitzung 40 Sekunden lang inaktiv ist.


Testen Sie die Anwendung

Um die Anwendung zu testen, müssen Sie Twilio Sandbox für WhatsApp einrichten, Ihren Anwendungsendpunkt öffentlich zugänglich machen und die Endpunkt-URL in der Sandbox-Konfiguration als Webhook hinzufügen.

Richten Sie Twilio Sandbox für WhatsApp ein

Gehe zum Twilio-Konsole , navigieren Sie zu Nachricht > Ausprobieren > WhatsApp-Nachricht senden .


Twilio-Konsole


Befolgen Sie die Anweisungen auf der Seite, um eine Verbindung zur Sandbox herzustellen, indem Sie eine WhatsApp-Nachricht von Ihrem Gerät an die angegebene Twilio-Nummer senden, um eine erfolgreiche Verbindung mit der WhatsApp-Sandbox herzustellen. Ebenso müssen andere Personen, die Ihre App mit ihren jeweiligen Nummern testen möchten, das gleiche Verfahren befolgen.

Machen Sie Ihren Webhook mit ngrok zum Testen verfügbar

Öffnen Sie nun ein Shell-Terminal und führen Sie den folgenden Befehl aus, um ngrok zu starten und Ihre lokale ASP.NET Core-App verfügbar zu machen, indem Sie <localhost-url> durch die vollständige URL Ihres ursprünglich kopierten Localhosts ersetzen:


 ngrok http <localhost-url>


ngrok generiert eine öffentliche URL, die Anfragen an Ihre lokale ASP.NET-App weiterleitet. Suchen Sie im ngrok-Terminalfenster nach der Weiterleitungs-URL mit der Bezeichnung „Forwarding“ und kopieren Sie sie.


Weiterleitungs-URL


Gehen Sie zurück zur Twilio Try WhatsApp-Seite, klicken Sie auf Sandbox-Einstellungen und ändern Sie die Endpunkt-URL „Wenn eine Nachricht eingeht“ durch die von ngrok generierte Weiterleitungs -URL sowie die Route „/Trivia “ und stellen Sie sicher, dass die Methode auf „POST“ eingestellt ist. Klicken Sie dann auf Speichern, um die neue Sandbox-Konfiguration zu speichern.


Twilio-Sandbox


Projektdemo

Führen Sie Ihr ASP.NET Core-Projekt mit dem folgenden Befehl aus:


 dotnet run


Testen Sie nun Ihre Anwendung, indem Sie im ersten Gespräch eine Nachricht mit der Twilio Sandbox-Nummer senden.


Testen Sie Ihre Anwendung in WhatsApp


Abschluss

Durch die Nutzung der Leistungsfähigkeit der Twilio-Plattform und WhatsApp haben Sie ein fesselndes Quizspielerlebnis geschaffen, das die Benutzer genießen können. Sie haben außerdem gelernt, wie Sie Daten aus Sitzungen speichern und abrufen.


Es gibt mehrere Möglichkeiten, dieses Projekt zu verbessern. Sie können dieses Projekt weiter verbessern, indem Sie einen Timer hinzufügen, Ausnahmen behandeln, Benutzern die Auswahl des Schwierigkeitsgrads ermöglichen und den gewählten Schwierigkeitsgrad als Abfrageparameter über die Trivia-API-URL anwenden (z. B https://the-trivia-api.com/api/questions?difficulty=hard ). Darüber hinaus können Sie die Möglichkeit prüfen, eine Lösung zu entwickeln, die es Benutzern ermöglicht, Umfragen über WhatsApp auszufüllen.