https://d226lax1qjow5r.cloudfront.net/blog/blogposts/build-a-secret-santa-app-with-blazor/blog_secret-santa_blazor_1200x600.jpg

Erstellen Sie eine Wichtel-App mit Blazor

Zuletzt aktualisiert am December 18, 2020

Lesedauer: 13 Minuten

Der Advent ist eine Zeit der Vorfreude. Natürlich gibt es eine zentrale spirituelle Erwartung, die viele von uns in der Vorweihnachtszeit empfinden. Es gibt auch die Vorfreude auf eine freie Zeit, in der wir uns entspannen und uns mit unseren Familien an unseren Traditionen erfreuen können.

Im Geiste des C#-Adventmöchte ich Ihnen mitteilen, wie meine Familie ihre Traditionen in diesen schwierigen Zeiten aufrechterhalten wird. Dieses Jahr habe ich eine Blazor-App gebaut, um unser jährliches Wichtelspiel zu virtualisieren. Sie ermöglicht es den Teilnehmern, sich mit ihrer Telefonnummer zu registrieren und ihnen mitzuteilen, wem sie ein Geschenk schicken sollen.

Das Problem

Jedes Jahr tauschen wir ein Wichtelgeschenk aus. Meine Frau wendet sich an alle Familienmitglieder, um zu erfahren, wer mitmachen möchte. Die Zahl schwankt, je nachdem, wie viel Engagement wir von den jüngeren Familienmitgliedern bekommen. In der Regel haben wir am Ende etwa fünfzehn Teilnehmer.

Theresa kauft dann Karten für jeden Teilnehmer und gibt die Spielregeln ein. Zum Beispiel: Gib nicht mehr als $xx aus. Dann steckt sie alle Karten in Umschläge, und an Thanksgiving (dem vierten Donnerstag im November) kommen wir zusammen, um die Karten zu verteilen.

Jedes Jahr stoßen wir auf ein Problem: Immer sind einige Teilnehmer beim Thanksgiving-Dinner nicht anwesend. Unsere Familie ist gleichmäßig auf New York, New Jersey und Florida verteilt. Dies stellt ein praktisches Problem dar, da wir nicht zufällig jemandem, der nicht anwesend ist, ein Wichtelgeschenk zuweisen können, da er sich möglicherweise selbst beschenken könnte. In der Vergangenheit konnten wir dieses Problem immer umgehen, indem eine Person, die nicht teilnimmt, die nicht anwesenden Personen auswählt, um sicherzustellen, dass sie sich nicht selbst beschenken. Danach adressiert meine Frau alle Umschläge an die entsprechenden Personen und schickt sie los.

In diesem Jahr fehlten nicht nur ein oder zwei Personen, sondern ein Dutzend, und da niemand anwesend war, um die Auswahl zu schlichten und sicherzustellen, dass sich niemand selbst erwischt, mussten wir kreativ werden.

Direkt zum Code springen

Wenn Sie dieses Tutorial überspringen und Ihr eigenes Wichtelspiel starten möchten, finden Sie den gesamten Code in GitHub

Voraussetzungen

  • Sie benötigen das neueste .NET SDK

  • Ich verwende Visual Studio 2019 für diese Demo. Sie können VS Code verwenden, wenn Sie möchten

  • Ich werde Folgendes verwenden Postgres für diese Demo verwenden. Für die Zwecke dieser Demo nehme ich an, dass Sie den Server eingerichtet haben. Sie können jede beliebige Datenbank verwenden, solange Sie den Datenbankkontext für diese aktualisieren

  • Ich habe dies auf Azure bereitgestellt - wenn Sie sich dafür entscheiden, ist das Ihre Sache, aber um dies auszuführen, benötigen Sie nur IIS Express oder

Vonage API-Konto

Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.

In diesem Lernprogramm wird auch eine virtuelle Telefonnummer verwendet. Um eine zu erwerben, gehen Sie zu Rufnummern > Rufnummern kaufen und suchen Sie nach einer Nummer, die Ihren Anforderungen entspricht.

Das Projekt erstellen

Unser erster Schritt besteht darin, unser Projekt zu erstellen. Navigieren Sie zu Ihrem Entwicklungsverzeichnis und führen Sie den folgenden Befehl in Ihrem Terminal aus:

dotnet new blazorserver --no-https -n SecretSanta

Dieser Befehl erstellt einen Ordner und ein Projekt namens SecretSanta. ausführen cd SecretSanta um in dieses Verzeichnis zu navigieren und dann die folgenden Befehle auszuführen:

dotnet add package Vonage
dotnet add package Microsoft.AspNetCore.Components.Authorization
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL

Datenmodell erstellen

Wir werden das Entity Framework Core um alle unsere Daten zu verarbeiten. Wie ich bereits erwähnt habe, verwende ich dafür Postgres, aber es gibt keine übergreifende Notwendigkeit, Postgres zu verwenden. Sie können jede beliebige Datenbank verwenden, die Ihnen zusagt.

Erstellen Sie eine Datei namens SecretSantaParticipant. und fügen Sie ihr Folgendes hinzu:

public class SecretSantaParticipant
{
    [Key]
    [Required]
    [Phone(ErrorMessage ="Phone Number must be a fully " +
        "formed phone number with no special charecters")]
    public string PhoneNumber { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public string Address { get; set; }

    public string GiftIdeas { get; set; }
    
    public string RequestId { get; set; }

    [ForeignKey("MatchForeignKey")]
    public SecretSantaParticipant Match { get; set; }

    public string Role { get; set; }

    public bool HasGiver { get; set; }
    
    [ForeignKey("GiverForeignKey")]
    public SecretSantaParticipant Giver { get; set; }
}

Diese Klasse wird das Datenmodell sein, das wir zwischen unserem Client und Server übergeben, um die Wichtelkonten zu verwalten.

Datenbankkontext erstellen

Erstellen Sie eine Datei namens SecretSantaContext.cs. Lassen Sie die SecretSantaContext Klasse erweitern DbContext erweitern und fügen Sie das Folgende hinzu.

private readonly IConfiguration _config;
public DbSet<SecretSantaParticipant> Participants { get; set; }

public SecretSantaContext(IConfiguration config) => _config = config;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
    optionsBuilder.UseNpgsql(_config["CONNECTION_STRING"]);

Hinweis: Hier nehmen Sie alle Änderungen vor, um eine andere Datenbank zu verwenden, wenn Sie dies wünschen

Einen Authentifizierungsanbieter erstellen

Wir verwenden die Vonage Verify API um die Anmeldung für unsere Benutzer zu verwalten. Wir werden eine benutzerdefinierte AuthenticationStateProvider die den Anmeldestatus für unsere Benutzer verwaltet. Erstellen Sie eine neue Datei AuthProvider.cs und lassen Sie die AuthProvider Klasse erweitern AuthenticationStateProvider.

In der AuthProvider Klasse fügen Sie ein privates ClaimsIdentiy Mitglied namens _identity:

private ClaimsIdentity _identity = new ClaimsIdentity();

Wir initialisieren diese Anspruchsidentität zunächst anonym, so dass der Benutzer keine Ansprüche hat, wenn er zum ersten Mal auf unserer Seite ankommt, was bedeutet, dass er eine Anmeldesequenz abschließen muss.

Autorisierungsstatus abrufen

Als Nächstes wollen wir eine Möglichkeit schaffen, den Authentifizierungsstatus durch Überladen der GetAuthenticationStateAsync Methode. Diese Methode wird einen Authentifizierungsstatus mit unserer Identität zurückgeben.

public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
    return await Task.FromResult(new AuthenticationState(new ClaimsPrincipal(_identity)));
}

Autorisierungsstatus aktualisieren

Dieser Statusanbieter wird auf die Sitzung eines bestimmten Benutzers beschränkt und teilt unserer Anwendung mit, worauf sie auf einer bestimmten Seite Zugriff haben darf. Folglich brauchen wir eine Möglichkeit, den Authentifizierungsstatus zu aktualisieren.

Dazu fügen wir eine Login- und eine Logout-Methode hinzu. Die Login-Methode AuthorizeUser erstellt eine neue ClaimsIdentity mit der Telefonnummer des Benutzers und seiner Rolle (wenn er ein Administrator ist, kann er mehr Dinge sehen). Sie benachrichtigt dann jeden, der sich die AuthProvider dass sich der Autorisierungsstatus geändert hat:

public void AuthorizeUser(SecretSantaParticipant participant)
{
    var claims = new[] { new Claim(ClaimTypes.Name, participant.PhoneNumber) };
    claims.Append(new Claim(ClaimTypes.Role, participant.Role));
    _identity = new ClaimsIdentity(claims,"apiauth_type");            
    var user = new ClaimsPrincipal(_identity);
    NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
}

Umgekehrt setzt die LogOutUser Methode den Wert ClaimsIdentity auf anonym zurückgesetzt und benachrichtigt alle, die den State Provider abhören, dass sie den Auth-Status aktualisiert hat.

public void LogOutUser()
{
    _identity = new ClaimsIdentity();
    var user = new ClaimsPrincipal(_identity);
    NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
}

Aufbau eines Wichteldienstes

Wir fügen einen in die Abhängigkeit injizierbaren Dienst hinzu, der es uns ermöglicht, alle Backend-Aufgaben zu erledigen, die unsere App erledigen muss. Dieser Dienst übernimmt die Verifizierung, das Lesen und Schreiben aus der Datenbank und das Senden von Nachrichten an unsere Teilnehmer. Erstellen Sie eine Datei namens SecretSantaService.cs.

Wir werden drei Dinge in unsere Abhängigkeit injizieren SecretSantaService:

  1. Unser VonageClient die alle Vonage-API-Anfragen für uns bearbeiten wird

  2. Unser SecretSantaContext die alle unsere Verbindungen zur Datenbank vermitteln wird

  3. Ein IConfiguration Objekt, das uns Zugriff auf die Konfiguration der Anwendung gibt

Erklären Sie diese als solche:

private readonly VonageClient _client;
private readonly SecretSantaContext _db;
private readonly IConfiguration _config;

Und dann injizieren Sie sie über den Konstruktor in unseren Dienst:

public SecretSantaService(VonageClient client, SecretSantaContext context, IConfiguration config)
{
   _client = client;
   _db = context;
   _config = config;
}

Eine Verify-Anfrage erstellen

Wir werden die Telefonnummer des Teilnehmers verwenden, um seinen Zugang zu seinem Account zu verifizieren. Diese Methode wird eine Art 1FA für die Anmeldung schaffen. Ich würde 1FA unter keinen Umständen verwenden, wenn ich eine sichere Anmeldung bräuchte, aber da dies nur ein lustiges Familienspiel ist und unser Ziel die Verifizierung der Telefonnummer ist, werde ich es dabei belassen.

Um die 1FA zu starten, fügen wir eine Methode hinzu, die die Verifizierung startet und die ID des Verify Kickoffs zurückgibt. Dies geschieht mit der Vonage Verify API. Zu diesem Zeitpunkt ist es nur eine einzige Codezeile:

public async Task<string> StartVeriy(string number)
{
   return (await _client.VerifyClient.VerifyRequestAsync(
       new VerifyRequest 
       { 
           Brand = "North Pole Access", 
           SenderId = _config["VONAGE_NUMBER"],
           Number= number,
           WorkflowId = VerifyRequest.Workflow.SMS,
           PinExpiry=300
       }
       )).RequestId;
}

Handle-Bestätigung

Wenn ein Benutzer seine Nummer eingibt, um sich anzumelden oder seinen Account zu erstellen, können wir die Vonage Verify API bitten, eine Verifizierungsanfrage zu stellen. Wir können dies mit der VerifyCheck Methode im Vonage Verify Client:

public async Task<bool> ConfirmCode(string id, string code)
{
   try
   {
       var result = await _client.VerifyClient.VerifyCheckAsync(new VerifyCheckRequest { Code = code, RequestId = id });
       return true;
   }
   catch (VonageVerifyResponseException)
   {
       return false;
   }            
}

Shuffle-Benutzer

Bei der nächsten Methode werden die Benutzer gemischt und eine Aufgabe für das Wichtelspiel verteilt. Diese Methode geht alle Benutzer durch, die noch kein Wichtelspiel haben, und gibt ihnen nach dem Zufallsprinzip eine Auswahl aus dem Pool der Benutzer, die noch kein Wichtelspiel haben Giver noch nicht haben.

public async Task ShuffleUsers()
{
   var rnd = new Random(DateTime.UtcNow.Second);
   
   var participants = _db.Participants.ToList();
   while (participants.Any(x => !x.HasGiver))
   {
       var participant1 = participants.First(x => !x.HasGiver);
       var unmatched = participants.Where(x => x.Match == null && x.PhoneNumber !=participant1.PhoneNumber);
       if(unmatched.Count() == 0)
       {
           System.Diagnostics.Debug.WriteLine("encountered Edge case");
           var match = participants.First(x => x.PhoneNumber != participant1.PhoneNumber);
           participant1.Giver = match;
           participant1.Match = match.Match;
           match.Match.Giver = participant1;
           match.Match = participant1;
           participant1.HasGiver = true;                    
       }
       else
       {
           var match = unmatched.ToList().ElementAt(rnd.Next(unmatched.Count() - 1));
           participant1.Giver = match;
           participant1.HasGiver = true;
           match.Match = participant1;                    
       }                
   }
   await _db.SaveChangesAsync();
}

Informieren Sie die Teilnehmer

Jetzt, wo die Nutzerinnen und Nutzer gemischt sind, müssen wir allen mitteilen, wer ihr Spiel ist!

Dazu werden wir die Vonage SMS API verwenden. Wir werden eine Schleife durch unsere Teilnehmer ziehen und ihnen mitteilen, wer ihr Wichtel ist, wie viel sie ausgeben sollen und wohin sie ihr Geschenk schicken sollen. Ich mache diesen Teil mit einem Vonage LVN, der auf eine Nachricht pro Sekunde gedrosselt ist. Daher lasse ich die App 1 Sekunde zwischen den Anfragen warten. Da wir einige jüngere Teilnehmer in diesem Spiel haben, werden wir ihnen sagen, dass der Weihnachtsmann ihre Hilfe braucht!

public async Task NotifyUsers()
{
   foreach(var participant in _db.Participants)
   {
       var message = $"Hello {participant.Name} this is Santa. " +
           $"I'm desperately busy up here at the North Pole and need your help. " +
           $"Could you help me out and find a gift for {participant.Match.Name}? " +
           $"It doesn't need to extravagant, I wouldn't spend more than $25." +
           $"You can send the gift directly to them at: {participant.Match.Address}. ";
       if (!string.IsNullOrEmpty(participant.Match.GiftIdeas))
       {
           message += $"They wrote me with some ideas of what to get them: {participant.Match.GiftIdeas}";
       }
       await _client.SmsClient.SendAnSmsAsync(new SendSmsRequest
       {
           To=participant.PhoneNumber,
           From=_config["VONAGE_NUMBER"],
           Text=message
       });
       Thread.Sleep(1000);
   }
}

Updates senden

Es wird nicht viel geben, was ein Benutzer nach der Anmeldung konfigurieren kann, aber ich habe beschlossen, ihn seine Adresse und die Ideen, die er seinem Wichtelgeschenk geben möchte, ändern zu lassen. Wenn ein Benutzer seinen Account ändert, schicken wir eine SMS an den Schenkenden, um ihn über die Änderung zu informieren:

public async Task NotifyUserOfUpdate(SecretSantaParticipant participant)
{
   if(participant.Match != null)
   {
       var msg = $"Hello, this is Santa again, just wanted to let you know that your match {participant.Name} sent me some updates:" +
           $" Their Address is {participant.Address}.";
       if (!string.IsNullOrEmpty(participant.GiftIdeas))
       {
           msg += $" And they indicated they'd want {participant.GiftIdeas}";
       }
       await _client.SmsClient.SendAnSmsAsync(new SendSmsRequest
       {
           To = participant.Match.PhoneNumber,
           From = _config["VONAGE_NUMBER"],
           Text = msg
       });
   }
}

Middleware konfigurieren

Hierfür verwenden wir mehrere Middleware-Teile. Wir verwenden den Datenbankkontext, um eine Verbindung zu unserer Datenbank aufrechtzuerhalten. Wir verwenden den VonageClient um API-Anfragen an Vonage zu stellen, und wir verwenden ein Konfigurationsobjekt, um unsere Vonage-Nummer abzurufen. Wir verwenden unser AuthProvider um unseren Autorisierungsstatus abzurufen.

Wir müssen alle diese Dienste bei unserer App registrieren. Zu diesem Zweck gehen Sie in Startup.cs und finden Sie die ConfigureServices Methode. Fügen Sie das Folgende hinzu:

services.AddDbContext<SecretSantaContext>();
var creds = Credentials.FromApiKeyAndSecret(Configuration["API_KEY"], Configuration["API_SECRET"]);
services.AddSingleton(new VonageClient(creds));
services.AddScoped<SecretSantaService>();
services.AddScoped<AuthenticationStateProvider, AuthProvider>();

Nachdem alle Dienste eingerichtet sind, müssen wir nun sicherstellen, dass wir Authentifizierung und Autorisierung aktivieren, um alles zu autorisieren. Bleiben Sie in der Startup.cs Datei und gehen Sie zu der Configure Methode und fügen Sie die folgenden zwei Zeilen hinzu:

app.UseAuthorization();
app.UseAuthentication();

Erstellen des Frontends

Nachdem wir das ganze Backend-Zeug ausgearbeitet haben, müssen wir nur noch unser Frontend erstellen. Da wir eine Autorisierungskomponente verwenden, um unseren Autorisierungsstatus an alle Komponenten weiterzugeben, müssen wir zuerst die gesamte Anwendung in eine CascadingAuthenticationState Komponente verpacken - öffnen Sie App.razor und umgeben Sie die gesamte Anwendung mit <CascadingAuthenticationState></CascadingAuthenticationState> Tags.

Hinzufügen einer Anmeldekomponente

Fügen Sie eine Login.razor Datei unter dem Ordner /Pages Hier fügen wir einfach eine Eingabe für die Anmeldung und eine Schaltfläche für die eigentliche Anmeldung hinzu, etwa so:

@inject SecretSantaService SecretSantaService
@inject SecretSantaContext Database
@inject NavigationManager NavigationManager
@using Vonage.Verify
<h3>Login</h3>
Phone Number:
<input class="input-group-text" @bind="_phoneNumber" />
<button class="btn-group-sm" @onclick="StartLogin">Login</button>
<br />
@if (_numberExists == false)
{
    <p1>Nubmer Not Registered</p1>
    <br />
}
<a href="/registration">Register here</a>

Als nächstes fügen wir eine Logik hinzu, um die Anmeldung durchzuführen. Wir starten eine Verify-Anfrage, die einen Code an den Benutzer sendet, wenn die Verifizierung noch nicht begonnen hat. Andernfalls wird er auf die Bestätigungsseite weitergeleitet, um sein OTP einzugeben.

@code {
    private string _phoneNumber;
    private bool? _numberExists;

    private async Task StartLogin()
    {
        if (!_phoneNumber.StartsWith("1"))
        {
            _phoneNumber = "1" + _phoneNumber;
        }
        var user = Database.Participants.Where(x => x.PhoneNumber == _phoneNumber).FirstOrDefault();
        if (user != null)
        {
            try
            {
                var verifyId = await SecretSantaService.StartVeriy(_phoneNumber);
                user.RequestId = verifyId;
                await Database.SaveChangesAsync();
                NavigationManager.NavigateTo($"/confirmCode/{verifyId}");
            }
            catch (VonageVerifyResponseException ex)
            {
                if (ex.Response.Status == "10")
                {
                    NavigationManager.NavigateTo($"/confirmCode/{user.RequestId}");
                }
            }
        }
        else
        {
            _numberExists = false;
        }
    }
}

Registrierungsseite hinzufügen

Wir möchten neuen Benutzern die Möglichkeit geben, ihre Telefonnummer in der App zu registrieren. Um dies zu tun, erstellen Sie eine neue RegistrationPage.razor Datei, und fügen Sie das folgende Formular hinzu:

@inject SecretSantaContext dbContext;
@inject SecretSantaService SecretSantaService
@inject NavigationManager NavigationManager
@inject Microsoft.Extensions.Configuration.IConfiguration Config
@using Vonage.Verify
@page "/registration"
<h3>Register</h3>

<div class="row">
    <div class="col-md-4">
        <EditForm Model="@participant" OnValidSubmit="CreateUser">
            <DataAnnotationsValidator />
            <ValidationSummary />
            Your Phone Number*:<br /><InputText id="phone" @bind-Value="participant.PhoneNumber" /><br />
            Your Name*:<br /><InputText id="Name" @bind-Value="participant.Name" /><br />
            Your Mailing Address*:<br /><InputText id="Address" @bind-Value="participant.Address" /><br />
            Gift ideas (For You!):<br /><InputText id="GiftIdeas" @bind-Value="participant.GiftIdeas" /><br />
            <button type="submit">Register</button>
            <p>*Required fields</p>
        </EditForm>
    </div>
</div>
@if (_userExistsAlready == true)
{
    <p>User exists already try <a href="/">logging in</a></p>
}
@if (!string.IsNullOrEmpty(_error))
{
    <p><b>Error Encountered:</b> @_error</p>
}

Als Nächstes fügen wir eine Methode "create user" hinzu, die in der Datenbank prüft, ob der vorgeschlagene Benutzer bereits existiert. Ist dies nicht der Fall, wird der Benutzer eingefügt und ein Verify-Ereignis ausgelöst. Andernfalls wird Ihnen mitgeteilt, dass die Erstellung fehlgeschlagen ist, weil der Benutzer bereits existiert. Außerdem habe ich eine Admin-Telefonnummer, für die ich die App konfigurieren werde; diese Telefonnummer bestimmt, wer der Administrator des Spiels ist. Wenn sie registriert sind, ist ihre Rolle admin.

@code {
    private SecretSantaParticipant participant = new SecretSantaParticipant();
    private bool? _userExistsAlready;
    private string _error = "";
    private async Task CreateUser()
    {
        participant.PhoneNumber = participant.PhoneNumber.Replace("(", "");
        participant.PhoneNumber = participant.PhoneNumber.Replace(")", "");
        participant.PhoneNumber = participant.PhoneNumber.Replace("-", "");

        if (!participant.PhoneNumber.StartsWith("1"))
        {
            participant.PhoneNumber = "1" + participant.PhoneNumber;
        }
        var userExists = dbContext.Participants.Where(x => x.PhoneNumber == participant.PhoneNumber).Any();
        if (!userExists)
        {

            try
            {
                if (participant.PhoneNumber == Config["ADMIN_NUMBER"])
                {
                    participant.Role = "admin";
                }
                else
                {
                    participant.Role = "user";
                }

                var verifyRequestId = await SecretSantaService.StartVeriy(participant.PhoneNumber);
                participant.RequestId = verifyRequestId;
                dbContext.Participants.Add(participant);
                dbContext.SaveChanges();
                NavigationManager.NavigateTo($"/confirmCode/{verifyRequestId}");
            }
            catch (VonageVerifyResponseException ex)
            {
                _error = ex.Response.ErrorText;
            }
        }
        else
        {
            _userExistsAlready = true;
        }
    }
}

Anmeldung abschließen

Nachdem jemand einen Account erstellt oder versucht hat, sich anzumelden, müssen wir ihn auf eine Seite weiterleiten, auf der er bestätigen kann, dass er den richtigen Code hat. Sie werden feststellen, dass nach dem Versenden der Verify-Anfrage, die NavigationManager den Benutzer zu einer neuen URL weiterleitet: NavigationManager.NavigateTo($"/confirmCode/{verifyRequestId}"); - Durch diesen Vorgang wird eine neue Seite geöffnet. Erstellen Sie eine neue Razor-Komponente namens CodeConfirmationPage.razor. Diese Seite nimmt einen Parameter durch den Pfad - die Verifizierungs-ID, die schließlich die Code-Bestätigung versuchen wird. Diese Seite enthält ein einfaches Eingabefeld und eine Schaltfläche, mit der wir die Bestätigung versuchen können. Wenn die Authentifizierung erfolgreich ist, navigieren wir zurück zur Root-Seite, die nun in der Lage ist, zum Rest der App zu leiten.

@using Microsoft.AspNetCore.Identity
@inject SecretSantaService VonageService
@inject SecretSantaContext db
@inject NavigationManager NavigationManager
@inject AuthenticationStateProvider Provider

@page "/confirmCode/{VerifyRequestId}"

<h3>Confirm Code!</h3>
<input class="input-group-text" @bind="_code" />
<button class="btn-group-lg" @onclick="CheckCode">Confirm</button>

@if (_authenticated == false)
{
    <p>Authentication Successful</p>
}

@code {
    [Parameter]
    public string VerifyRequestId { get; set; }
    private string _code;
    private bool? _authenticated;

    private async Task CheckCode()
    {
        _authenticated = await VonageService.ConfirmCode(VerifyRequestId, _code);
        if (_authenticated == true)
        {
            var user = db.Participants.Where(x => x.RequestId == VerifyRequestId).FirstOrDefault();
            ((AuthProvider)Provider).AuthorizeUser(user);
            NavigationManager.NavigateTo("/");
        }
    }
}

Account Seite

Die letzte Seite, die wir hinzufügen müssen, ist die eigentliche Account-Seite. Hier gibt es einen Unterschied in der Zugriffsebene, je nachdem, ob der Benutzer ein Administrator ist oder nicht. Wenn das eigentliche Spiel gestartet wird, kann der Administrator überprüfen, ob alle Teilnehmer korrekt angemeldet sind, und er kann die Nachricht an alle senden, dass das Spiel begonnen hat.

Im Anzeigebereich dieser Seite zeigen wir jedem seinen Namen und seine Account-Informationen an, sowie die Personen, mit denen er/sie zusammengeführt wird (vorausgesetzt, dass keine Übereinstimmung mehr ansteht). Wir lassen auch die Felder für die Adresse und die Geschenkidee bearbeitbar, damit wir sie aktualisieren können, falls sich jemand dafür entscheidet. Erstellen Sie eine Razor-Datei namens AccountComponent.razor und fügen Sie das Folgende hinzu:

@inject SecretSantaContext Db
@inject AuthenticationStateProvider Provider
@inject NavigationManager NavigationManager
@inject SecretSantaService SecretSantaService
@using System.Security.Claims
<h3>Accounts</h3>
<table class="table-bordered">
    <tr>
        <th>Your Name</th>
        <td>@participant.Name</td>
    </tr>
    <tr>
        <th>Your Address</th>
        <td><input class="input-group" @bind="participant.Address" /></td>
    </tr>
    <tr>
        <th>Gift Ideas For You</th>
        <td><input class="input-group" @bind="participant.GiftIdeas" /></td>
    </tr>
    @if (participant.Match != null)
    {
        <tr>
            <th>Your Secret Santa</th>
            <td>@participant.Match.Name</td>
        </tr>
        <tr>
            <th>Gift Ideas</th>
            <td>@participant.Match.GiftIdeas</td>
        </tr>
        <tr>
            <th>Your Secret Santa's Address</th>
            <td>@participant.Match.Address</td>
        </tr>
    }
    else
    {
        <tr>
            <th>Status</th>
            <td>Pending match</td>
        </tr>
    }
</table>
@if (_isAdmin)
{
    <h3>Admin Section</h3>
    <table class="table-bordered">
        <thead>
            <tr>
                <th>Name</th>
                <th>Phone Number</th>
                <th>Address</th>
                <th>Gift ideas</th>
                <th>Matched?</th>
            </tr>
        </thead>
        @foreach (var par in _participants)
        {
            <tr>
                <td>@par.Name</td>
                <td>@par.PhoneNumber</td>
                <td>@par.Address</td>
                <td>@par.GiftIdeas</td>
                <td>@(par.Match!=null)</td>
            </tr>
        }
    </table>
    <button @onclick="Shuffle" class="btn-group-lg">Shuffle And Send</button>
    <button @onclick="SecretSantaService.NotifyUsers">Notify Participants</button>
    <br />
}
<p>@msg</p>
<button style="cursor:pointer" @onclick="UpdateAccount">Update Account</button>
<a @onclick="Logout" href="">Log Out</a>

Für den Code haben wir eine Methode, die die Seite für uns initialisiert. Angenommen, die Identität unseres Authentifizierungsstatus ist ein Admin. In diesem Fall werden wir auch die Datenbank abfragen, um die Liste der aktuellen Teilnehmer im Spiel zu erhalten und sie in einer separaten Tabelle anzuzeigen. Wir haben eine Schaltfläche, um die Benutzer zu mischen und ihnen ein Wichtelmännchen zuzuweisen, und dann haben wir die Schaltfläche des Administrators, um den Wettbewerb zu starten, mit dem der Weihnachtsmann den Gruß an alle verschickt.

@code {
    SecretSantaParticipant participant = new SecretSantaParticipant();
    List<SecretSantaParticipant> _participants = new List<SecretSantaParticipant>();
    string msg;
    bool _isAdmin;

    protected override async Task OnInitializedAsync()
    {
        var user = (await ((AuthProvider)Provider).GetAuthenticationStateAsync()).User.Claims.First(x => x.Type == ClaimTypes.Name).Value;
        participant = Db.Participants.ToList().FirstOrDefault(x => x.PhoneNumber == user);
        _isAdmin = participant.Role == "admin";
        if (_isAdmin)
        {
            _participants = Db.Participants.ToList();
        }
        StateHasChanged();
    }

    private async void Shuffle()
    {
        await SecretSantaService.ShuffleUsers();
    }

    private void Logout()
    {
        ((AuthProvider)Provider).LogOutUser();

    }
    private async void UpdateAccount()
    {
        var par = Db.Participants.FirstOrDefault(x => x.PhoneNumber == participant.PhoneNumber);
        par = participant;

        await Db.SaveChangesAsync();
        msg = "Account Updated";

        try
        {
            await SecretSantaService.NotifyUserOfUpdate(par);
        }
        catch (Exception ex) { msg = ex.Message; }
        StateHasChanged();
    }
}

Einrichten der Routen im Index

Die letzte Code-bezogene Sache, die wir tun müssen, um die App einzurichten, ist, den Inhalt der Index.razor Datei durch eine AuthorizeViewzu ersetzen, die die Account-Seite anzeigt, wenn der Auth-Status autorisiert ist, und andernfalls die Login-Seite. Fügen Sie in der Datei index.razor Folgendes hinzu:

@page "/"

<AuthorizeView>
    <Authorized>
        <AccountComponent></AccountComponent>
    </Authorized>
    <NotAuthorized>
        <Login></Login>
    </NotAuthorized>
</AuthorizeView>

Konfiguration

Nachdem wir nun die Anwendung geschrieben haben, müssen wir die Datenbank einrichten und die entsprechenden Umgebungsvariablen zur Anwendung hinzufügen.

appsettings.json

Öffnen Sie Ihre appsettings.json Datei und fügen Sie ihr die folgenden Schlüssel hinzu:

"CONNECTION_STRING": "Host=localhost;Database=secretsantausers;User Id=username;Password=password;Port=5432",
"API_KEY": "API_KEY",
"API_SECRET": "API_SECRET",
"VONAGE_NUMBER": "VONAGE_NUMBER"

Setzen Sie die API_KEY und API_SECRET mit Ihrem API-Schlüssel und Geheimnis aus Ihrem Vonage Dashboard. Setzen Sie die VONAGE_NUMBER auf eine Ihrer Vonage virtuellen Numbers. Legen Sie die Admin-Nummer auf die Handynummer der Person fest, die Sie als Administrator des Spiels einsetzen möchten (vermutlich Sie selbst). Schließlich setzen Sie die CONNECTION_STRING auf die Verbindungszeichenfolge Ihrer Datenbank.

Migrieren Sie die Datenbank

Schließlich müssen wir noch die Datenbank migrieren. Dazu benötigen Sie das Entity Framework Tool:

dotnet tool install --global dotnet-ef

Führen Sie dann das Fluent-Tool aus, um die Migration zu erstellen:

dotnet ef migrations add initial_create

Führen Sie schließlich das Update-Tool von fluent aus, um alle entsprechenden Migrationen durchzuführen:

dotnet ef database update

Schlussfolgerung

Und das war's! Jetzt können Sie die Anwendung starten, indem Sie entweder auf die Schaltfläche "Play" in IIS Express klicken oder mit dem Befehl dotnet run Befehl von Ihrem Terminal aus starten. Sie sind auf jeden Fall bereit!

Andere Ressourcen

  • Einen umfassenden Überblick über die Verify API finden Sie auf unserer Dokumentations-Website.

  • Weitere Einsatzmöglichkeiten unserer SMS API finden Sie hier

  • Den gesamten Quellcode dieser Demo finden Sie auf GitHub

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/73d57fd8eb/stevelorello.png
Steve LorelloVonage Ehemalige

Ehemaliger .NET Developer Advocate @Vonage, polyglotter Software-Ingenieur, AI/ML