https://a.storyblok.com/f/270183/63087/ed0a04a7f1/blog_secret-santa_blazor_1200x600.jpg

Crie um aplicativo de Amigo Secreto com o Blazor

Publicado em December 18, 2020

Tempo de leitura: 14 minutos

O Advento é uma época de expectativa. É claro que existe uma expectativa espiritual fundamental que muitos de nós sentimos na preparação para o Natal. Há também a expectativa pelas férias, para relaxar e celebrar com nossas famílias, seguindo nossas tradições.

No espírito do C# Advent, gostaria de compartilhar como minha família vai manter suas tradições nestes tempos difíceis. Este ano, criei um aplicativo em Blazor para virtualizar nosso jogo anual de Amigo Secreto. Ele permite que os participantes se cadastrem com seu número de telefone e recebe uma mensagem informando para quem devem enviar um presente.

O problema

Todos os anos fazemos uma troca de presentes do “Amigo Secreto”. Minha esposa entra em contato com todos os membros da nossa família para saber quem gostaria de participar. O número varia de acordo com o nível de participação dos membros mais jovens da família. Normalmente, no final, temos cerca de quinze participantes.

Theresa então compra cartões para cada participante e preenche as regras do jogo. Por exemplo, não gastar mais do que $xx. Em seguida, ela coloca todos os cartões em envelopes e, no Dia de Ação de Graças (a quarta quinta-feira de novembro), nos reunimos para distribuir os cartões.

Todos os anos nos deparamos com uma situação: invariavelmente, alguns participantes não estão presentes no jantar de Ação de Graças, já que nossa família está distribuída igualmente entre Nova York, Nova Jersey e Flórida. Isso gera um problema prático, pois não podemos designar aleatoriamente um “Amigo Secreto” para alguém que não está presente, já que essa pessoa poderia acabar se sorteando a si mesma. No passado, sempre conseguimos contornar isso pedindo a uma pessoa que não estivesse participando para selecionar qualquer um que não estivesse presente, garantindo assim que não se sorteasse a si mesmo. Depois disso, minha esposa endereça todos os envelopes às pessoas certas e os envia.

Este ano, em vez de uma ou duas pessoas estarem ausentes, faltaram uma dúzia, e como não havia ninguém presente para arbitrar o processo de seleção e garantir que ninguém se escolhesse a si mesmo, precisamos ser criativos.

Ir direto para o código

Se você quiser pular este tutorial e organizar seu próprio jogo de Amigo Secreto, todo o código está disponível no GitHub

Pré-requisitos

  • Você precisará da versão mais recente do SDK do .NET

  • Eu uso o Visual Studio 2019 para esta demonstração. Você pode usar o VS Code, se quiser

  • Vou usar o Postgres para esta demonstração. Para fins desta demonstração, vou partir do princípio de que você já tem o servidor instalado. Você pode usar qualquer banco de dados que desejar, desde que atualize o contexto do banco de dados para ele

  • Eu implantei isso no Azure — se você decidir fazer o mesmo, a escolha é sua, mas, para executar isso, você só precisa do IIS Express ou

Criar o projeto

Nosso primeiro passo será criar nosso projeto. Acesse o diretório de desenvolvimento e execute o seguinte comando no terminal:

dotnet new blazorserver --no-https -n SecretSanta

Este comando criará uma pasta e um projeto chamados SecretSanta. Execute cd SecretSanta para acessar esse diretório e, em seguida, execute os seguintes comandos:

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

Criar modelo de dados

Vamos usar o Entity Framework Core para gerenciar todos os nossos dados. Como mencionei anteriormente, estou usando o Postgres para isso, mas não há nenhuma necessidade específica de usar o Postgres. Você pode usar qualquer banco de dados com o qual se sinta à vontade.

Crie um arquivo chamado SecretSantaParticipant. e adicione o seguinte a ele:

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

Essa classe será o modelo de dados que vamos trocar entre nosso cliente e nosso servidor para gerenciar as contas do Amigo Secreto.

Criar contexto de banco de dados

Crie um arquivo chamado SecretSantaContext.cs. Faça com que a SecretSantaContext classe herde DbContext e adicione o seguinte a ela.

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"]);

Observação: é aqui que você faria quaisquer alterações para usar um banco de dados diferente, caso quisesse

Criar um provedor de autenticação

Vamos usar a Verify API do Vonage Verify para gerenciar o login dos nossos usuários. Teremos um arquivo personalizado AuthenticationStateProvider que irá gerenciar o estado de login dos nossos usuários. Crie um novo arquivo AuthProvider.cs e faça com que a AuthProvider classe herde AuthenticationStateProvider.

Na AuthProvider classe, adicione um membro privado ClaimsIdentiy chamado _identity:

private ClaimsIdentity _identity = new ClaimsIdentity();

Estamos inicializando essa identidade de reivindicações de forma anônima inicialmente, para que o usuário não tenha nenhuma reivindicação ao acessar nossa página pela primeira vez, o que significa que ele precisará concluir um processo de login.

Obter estado de autenticação

A seguir, vamos fornecer uma maneira de obter o estado de autenticação sobrecarregando o GetAuthenticationStateAsync método. Esse método retornará um estado de autenticação com nossa identidade.

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

Atualizar o estado de autenticação

Esse provedor de estado será restrito à sessão de um usuário específico e informará ao nosso aplicativo a que ele tem permissão para acessar em uma determinada página. Consequentemente, precisamos de uma forma de atualizar o estado de autenticação.

Para isso, vamos adicionar um método de login e um de logout. O método Login AuthorizeUser criará um novo ClaimsIdentity com o número de telefone do usuário e sua função (se for um administrador, terá acesso a mais informações). Em seguida, ele notificará qualquer pessoa que esteja acompanhando o AuthProvider de que o estado de autenticação mudou:

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

Por outro lado, o LogOutUser método redefinirá o ClaimsIdentity para “anônimo” e notificará qualquer entidade que esteja monitorando o provedor de estado de que ele atualizou o estado de autenticação.

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

Crie um serviço de Amigo Secreto

Vamos adicionar um serviço com injeção de dependências para nos permitir realizar todas as tarefas de back-end necessárias ao nosso aplicativo. Esse serviço inclui o gerenciamento da verificação, a leitura e a gravação no banco de dados e o envio de mensagens aos nossos participantes. Crie um arquivo chamado SecretSantaService.cs.

Vamos injetar três dependências em nosso SecretSantaService:

  1. Nosso VonageClient que cuidará de todas as solicitações da API da Vonage para nós

  2. Nosso SecretSantaContext que irá mediar todas as nossas conexões com o banco de dados

  3. Um IConfiguration objeto, que nos dá acesso à configuração do aplicativo

Declare-os da seguinte forma:

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

E, em seguida, injetá-los em nosso serviço por meio do construtor:

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

Criar uma solicitação de Verify

Vamos usar o número de telefone do participante para verificar o acesso dele à conta. Esse método criará uma espécie de autenticação de fator único (1FA) para o login. Eu não usaria a autenticação de dois fatores (1FA) em nenhuma circunstância em que precisasse de um login seguro, mas, como se trata apenas de um jogo divertido para a família e nosso objetivo é Verify o número de telefone, vou deixar assim.

Para dar início ao 1FA, vamos adicionar um método para iniciar a verificação e retornar o ID do início do processo de verificação. Faremos isso usando a Verify API do Vonage. Neste momento, trata-se apenas de uma única linha de código:

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

Confirmação do identificador

Quando um usuário insere seu número para fazer login ou cria sua conta, podemos solicitar à Verify API do Vonage que realize uma solicitação de verificação. Podemos fazer isso usando o VerifyCheck método en el 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;
   }            
}

Misturar usuários

O próximo método irá embaralhar os usuários e distribuir uma designação para o jogo do Amigo Secreto. Esse método percorrerá todos os usuários que ainda não receberam uma designação para o Amigo Secreto e atribuirá a cada um deles, aleatoriamente, um nome do grupo de usuários que também ainda não receberam uma designação Giver ainda.

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

Informar os participantes

Agora que os usuários já se misturaram, precisamos dizer a todos quem é o par de cada um!

Para isso, vamos usar a SMS API da Vonage. Vamos percorrer a lista de participantes e informar a cada um quem é seu Amigo Secreto, quanto gastar e para onde enviar o presente. Estou fazendo essa parte com um LVN da Vonage, que limita a taxa de envio a uma mensagem por segundo. Por isso, farei com que o aplicativo espere 1 segundo entre as solicitações. Como temos alguns participantes mais jovens neste jogo, vamos dizer a eles que o Papai Noel precisa da ajuda deles!

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

Enviar atualizações

Bem, não haverá muitas opções de configuração disponíveis para o usuário após o cadastro, mas decidi permitir que ele altere seu endereço e as sugestões de presentes que deseja passar para o seu Amigo Secreto. Consequentemente, quando um usuário acessar e editar sua Account, enviaremos um SMS ao presenteador informando sobre a atualização:

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

Configurar o middleware

Estamos utilizando vários componentes de middleware para isso. Estamos usando o contexto do banco de dados para manter uma conexão com nosso banco de dados. Estamos usando o VonageClient para fazer solicitações de API à Vonage e estamos usando um objeto de configuração para obter nosso número da Vonage. Estamos usando nosso AuthProvider para obter nosso estado de autorização.

Vamos precisar registrar todos esses serviços em nosso aplicativo. Para isso, acesse Startup.cs e localize o ConfigureServices método. Adicione o seguinte a ele:

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

Com todos os serviços configurados, agora precisamos nos certificar de habilitar a autenticação e a autorização para autorizar tudo. Permaneça no Startup.cs arquivo e vá até o Configure e adicione as duas linhas a seguir a ele:

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

Criar o front-end

Com toda a parte de back-end resolvida, só falta construir nosso front-end. Como estamos usando um componente de autorização para propagar nosso estado de autorização para todos os componentes, precisaremos primeiro envolver todo o aplicativo em um CascadingAuthenticationState componente — abra o arquivo App.razor e envolver todo o aplicativo com as <CascadingAuthenticationState></CascadingAuthenticationState> .

Adicionar um componente de login

Adicione um Login.razor arquivo na pasta /Pages pasta; aqui, vamos apenas adicionar um campo de entrada para lidar com nosso login e um botão para efetivamente realizar o login, desta forma:

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

A seguir, vamos adicionar uma lógica para realizar o login. Vamos iniciar uma solicitação de verificação, que enviará um código ao usuário caso a verificação ainda não tenha começado. Caso contrário, ele será redirecionado para a página de confirmação para inserir sua senha de uso único (OTP).

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

Adicionar página de cadastro

Queremos permitir que novos usuários registrem seu número de telefone no aplicativo. Para isso, crie um novo RegistrationPage.razor arquivo e adicione o seguinte formulário a ele:

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

Em seguida, vamos adicionar um método de criação de usuário para verificar no banco de dados se o usuário proposto já existe. Se não existir, ele inserirá o usuário e iniciará um evento de Verify. Caso contrário, ele informará que a criação falhou porque o usuário já existe. Além disso, tenho um número de telefone de administrador para o qual vou configurar o aplicativo; esse número de telefone determinará quem é o administrador do jogo. Quando ele estiver registrado, sua função será 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;
        }
    }
}

Concluir o login

Depois que alguém cria um Account ou tenta fazer login, precisamos redirecioná-lo para uma página onde ele poderá confirmar se possui o código correto. Você notará que, após enviar a solicitação Verify, o NavigationManager redireciona o usuário para uma nova URL: NavigationManager.NavigateTo($"/confirmCode/{verifyRequestId}"); - essa ação abrirá uma nova página. Crie um novo componente Razor chamado CodeConfirmationPage.razor. Essa página receberá um parâmetro por meio do caminho — o ID de verificação, que, por fim, tentará a confirmação do código. Essa página terá um campo de entrada simples e um botão para que possamos tentar a confirmação. Se a autenticação for bem-sucedida, voltaremos para a página raiz, que agora poderá redirecionar para o restante do aplicativo.

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

Página da conta

A última página que precisamos adicionar é a página do Account propriamente dita. Esse acesso terá, na verdade, um nível diferente, dependendo se o usuário é administrador ou não. Quando o jogo estiver pronto para começar, o administrador poderá verificar se todos estão conectados corretamente e terá a possibilidade de enviar uma mensagem a todos informando que o jogo já começou.

Na seção de exibição desta página, mostraremos a todos o nome e as informações da Account, bem como com quem estão emparelhados (supondo que o emparelhamento não esteja mais pendente). Também deixaremos os campos de endereço e sugestão de presente editáveis para que, caso alguém opte por atualizá-los, possamos oferecer suporte a isso. Crie um arquivo Razor chamado AccountComponent.razor e adicione o seguinte:

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

Agora, quanto à parte do código, teremos um método para inicializar a página para nós. Suponhamos que a identidade do nosso estado de autenticação seja “admin”. Nesse caso, também faremos uma consulta ao banco de dados para obter a lista dos participantes atuais do jogo e exibi-los em uma tabela separada. Teremos um botão para embaralhar os usuários e designar a cada um um “Amigo Secreto”; em seguida, teremos o botão do administrador para dar início ao concurso, o que fará com que o Papai Noel envie a mensagem de felicitações a todos.

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

Configurar as rotas no índice

A última coisa relacionada ao código que precisamos fazer para configurar o aplicativo é substituir o conteúdo do Index.razor arquivo por um AuthorizeView, que exibirá a página da conta se o estado de autenticação for “autorizado” e, caso contrário, a página de login. No arquivo index.razor, adicione o seguinte:

@page "/"

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

Configuração

Agora que já criamos o aplicativo, precisamos configurar o banco de dados e adicionar as variáveis de ambiente adequadas ao aplicativo.

appsettings.json

Abra seu appsettings.json arquivo e adicione as seguintes chaves a ele:

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

Defina o API_KEY e API_SECRET com sua chave e senha da API do seu Painel da Vonage. Defina o VONAGE_NUMBER para um dos seus números virtuais da Vonage. Defina o número de administrador como o número de celular de quem você quiser que seja o administrador do jogo (provavelmente você mesmo). Por fim, defina o CONNECTION_STRING para a string de conexão do seu banco de dados.

Migrar o banco de dados

Por fim, precisaremos migrar o banco de dados. Para isso, você precisará da ferramenta Entity Framework:

dotnet tool install --global dotnet-ef

Em seguida, execute a ferramenta Fluent para criar a migração:

dotnet ef migrations add initial_create

Por fim, execute a ferramenta de atualização do Fluent para aplicar todas as migrações necessárias:

dotnet ef database update

Conclusão

E pronto! Agora você pode executar o aplicativo clicando no botão “Play” no IIS Express ou usando o dotnet run comando no seu terminal. De qualquer forma, está tudo pronto!

Outros recursos

  • Uma visão geral completa da Verify API está disponível em nosso site de documentação.

  • Você pode ver outras formas de uso da nossa SMS API aqui

  • Todo o código-fonte desta demonstração pode ser encontrado em GitHub

Compartilhar:

https://a.storyblok.com/f/270183/384x384/73d57fd8eb/stevelorello.png
Steve LorelloEx-funcionários da Vonage

Steve é um ex-membro da equipe da Vonage. Ele atuou como Developer Advocate .NET na Vonage, engenheiro de software full-stack poliglota, especializado em IA/ML