Arquivos Desenvolvimento de Aplicações | Core MVC
por Alcides Soares Filho | 10/01/2021 | Desenvolvimento de Aplicações | 0 Comentários
É muito fácil achar na Internet como mandar e-mails com a API do Sendgrid. Mas não existe quase nada sobre automação de campanhas de e-mail marketing usado a API v3 do SendGrid!
Campanhas de E-mail Marketing, automatizadas, como você sempre sonhou!
Se você já usa o SendGrid para enviar seus e-mails , já andou metade do caminho (veja meu artigo Adicionando serviço de E-mail no Core MVC, usando SendGrid).
O fato é que há coisas muito chatas de se fazer no Core MVC. Uma delas é formatar e-mails para envio. Outra é tentar programar eventos para acontecer no tempo. Uma campanha de e-mail marketing essencialmente tem que ter e-mails muito bonitos, responsivos, realmente vendedores. E que possam ser mandados sequencialmente assim que a pessoa se inscreve no seu site (como usuária, como interessada em receber alguma coisa), evento este que "dispara" e-mails de tempos em tempo, dando boas vindas (por exemplo) e depois oferecendo seus serviços ou produtos. Com o SendGrid você tem de graça tudo isso, até 6 mil e-mails por mês.
O que (as novas) Campanhas de Marketing do SendGrid Oferecem
Ferramentas de Criação e Edição de Modelos de E-mails
Biblioteca de modelos responsivos (onde você pode guardar seus templates também);
Ferramentas de criação e edição dos seus próprios modelos, começando do "zero". Você pode arrastar e soltar, escrever em HTML puro ou ambos.
Importação de imagens Na sua biblioteca particular).
Voce cria automações de e-mail de alto impacto em horas ou minutos – e não dias – com gatilhos simples e uma visão centralizada das mensagens e do tempo de sua série de e-mails da Campanha.
Aqui vamos dar um exemplo completo que dispara uma campanhade e-mails em sequência no SendGrid quando alguém se inscreve no seu site montado em Core MVC.
O e-mail cadastrado pelo seu sistema (no nosso exemplo através do Registro de Usuários do Identity), assim que é validado pelo controlador (e é salvo na tabela ASPNETUsers), é mandado também para uma Lista de Contatos do SendGrid. A essa lista está associada uma Campanha de Marketing, com um cronograma de envios de quantos e-mails você quiser. A grande vantagem é que para cada e-mail enviado, você sabe quem recebeu, quem não recebeu, quem recebeu e abriu o email, quem abriu e clicou no e-mail (e quantaz vezes).Tudo isso de graça e dentro do SendGrid. Veja neste vídeo curto.
Abra uma conta no SendGrid (ou acesse a sua) e:
Crie uma API para a Campanha (anote a chave secreta da APIKey, porque ela nnunca mais será mostrada). Depois de criar (ou se você já tem API), certifique-se que ela tenha "plenos poderes" insclusive para marketing.
CREATE API KEY (se não tiver ainda uma, se tiver pule)
CLIQUE NA ENGRENAGEM PARA EDITAR PODERES
ESCOLHA EDIT API KEY
ESCOLHA FULL ACCESS
Agora vamos para a (NOVA) área de Marketing. No menu esquerdo:
Clique em Marketing NEW
Clique em Contacts (Você vai ver uma lista chamada GLOBAL, que tem todos os contatos de todas as as listas. Esta lista não nos interessa)
Clique, no topo, em Create e escolha New List . De o nome de sua lista e salve. Logo abaixo da sua lista Global vai aparecer o nome de sua nova lista.
Agora que tem a sua lista, clique no nome dela (NAME). Vai aparecer a lista de todos seus e-mails (mas se a lista é nova, nenhum e-mail).
O importante neste momento é que a URL tem o endereço interno da identidade da lista no sistema, que vai ser usada na API. No meu caso, a URL está assim:
https://mc.sendgrid.com/contacts/lists/e8b61063-6f33-4963-b8fc-331723f21f6x
Guarde junto do segredo da chave de api SOMENTE a identidade da Lista:
e8b61063-6f33-4963-b8fc-331723f21f6x
No menu esquerdo:
No topo direiro, Create an Automation
Você poderia começar completamente do zero, selecionando a opção CUSTOM.
Escolha WELCOME. Já vem uma microcampanha pronta, que você pode editar e mudar o que quiser. Dê o nome para sua campanha (o default é Untitled Welcome Series)
Não se esqueça de salvar todas mudanças. clicando em SAVE no topo da página (nada intuitivo)
Clique em Automation Options e clique em Set Live (põe no ar!). Note que é aí que você pode duplicar uma campanha existente. Também nada intuitivo.
Clique em Automation, no topo da página à esquerda. A nossa campanha Teste vai aparecer como Draft (rascunho) e não como Live (Ao vivo!). É que a campanha não entra ao vivo se não:
Tiver um NOME
Tiver uma LISTA ESCOLHIDA
Ter definido um mode da pessoa sair da lista. Para simplificar, escolho i modo de saída global (válido para todas as listas): GLOBAL UNSUBSCRIBE
Em cada email que vai ser mandado, ter definido SUBJECT (ASSUNTO) e SENDER (e-mail de quem está mandando o e-mail). Se você não cadastrou, vai ter que ir em SENDERS PAGE e definir um e-mail de remetente (você vai ter que VERIFICAR esse e-mail para torná-lo válido para o SendGrid). Eu recomendo fazer a verificação do E-mail e do domínio de envio, assim as chances dos e-mails enviados caírem no SPAM dos destinatários caem praticamente a zero!.
Faça tudo que o SendGrid solicitar até que sua campanha, finalmente, saia de DRAFT para LIVE.
Finalmente, começando a programação no CORE MVC
Assim que conseguir isso, vamos finalmente para nosso velho Visual Studio. Para implementar o envio de e-mails, escolho o arquivo REGISTER.CSHMTL.CS, que é o controlador do registro de novos usuários na tabela ASPNETUSERS, do Identity.
Você pode escolher qualquer controlador seu que vai salvar um e-mail dentro da base de dados. Assim que a validação do modelo é feita dentro do controlador, você aproveita o embalo e envia o mesmo e-mail para a lista do SENDGRID, que está amarrada na sua campanha. Funciona que é uma chupeta.
Parte inicial do controlador
Você vai ter de instalar, aplicação, os seguintes pacotes (que inclusive substituem o newtowjson):
parte inicial do controlador (no caso register.cshtm.cs) em Areas/Identity/Pages/Account/
using PoupaTempoDigital.Services;
//pode ser necessário instalar os 4acima via Packate Manager
namespace PoupaTempoDigital.Areas.Identity.Pages.Account
//_emailSender;
private readonly RoleManager<AppRole> _roleManager;
SignInManager<AppUser> signInManager,
RoleManager<AppRole> roleManager,
// continua controlador ....
Eu prentendo, além do e-mail, passar para a minha lista SENDGRID nome e sobrenome. O Sendgrig tem mais de uma dezena de campos prontos na lista – e você pode definir mais campos customizados, quantos ou quais quiser.
Para isso criei, dentro do próprio controller, uma classe de modelo bem simples, logo após a tarefa Task OnGetAsync; Os nomes da variáveis tem que bater com os nomes padrão que o SendGrid já tem (e/ou com os nomes de campos customizados que você vier a criar para todos e-mails da sua lista):
modelo de dados a serem passados pelo register.cshtm.cs) em Areas/Identity/Pages/Account/
//MODELO DE DADOS
public class EmailSendgrid
Dentro do método POST do seu controle, no meu caso:
assim que o modelo é VALIDADO:
logo depois de validar o envio do post, gravar o usu&amp;aacute;rio, colocamos a "conversa" com a API da SENDGRID
//o controle tenta criar o usuário
//sucesso!!!
_logger.LogInformation("O usuário criou uma nova conta com senha.");
//COMEÇO****** COLOCANDO dados no sendgrid
var NovoEmail = new EmailSendgrid
first_name = user.FirstName,
last_name = user.LastName
//TROQUE PELOS DADOS DE ID DA SUA LISTA, CONFORME DICA NO COMEÇO DO ARTIGO
var lista_ID = "e8b61063-6f33-4963-b8fc-331723f2322D3";
string jsonString = "{" + ""list_ids":" + " ["" + lista_ID + ""]," + ""contacts":" + "[" + JsonSerializer.Serialize(NovoEmail) + "]}";
//PEGA A SEDRET KEY DA SUA API SEND GRID (QUE ESTA ARMAZENADA NO ARQUIVO APPSETTING.JSON)
var json = JsonSerializer.Deserialize<Object>(jsonString);
var client = new RestClient("https://api.sendgrid.com/v3/marketing/contacts");
var requisicao = new RestRequest(Method.PUT);
requisicao.AddHeader("content-type", "application/json");
requisicao.AddHeader("authorization", "Bearer " + API);
//requisicao.AddHeader("on-behalf-of", "");
requisicao.AddParameter("application/json", jsonString, ParameterType.RequestBody);
IRestResponse response = client.Execute(requisicao);
//******fim
//cria papéis se ainda não existem
if (!await _roleManager.RoleExistsAsync(Papeis.AdminEndUser))
await _roleManager.CreateAsync(new AppRole(Papeis.AdminEndUser));
if (!await _roleManager.RoleExistsAsync(Papeis.ClienteEndUser))
await _roleManager.CreateAsync(new AppRole(Papeis.ClienteEndUser));
//colaborador
if (!await _roleManager.RoleExistsAsync(Papeis.ColaboradorEndUser))
await _roleManager.CreateAsync(new AppRole(Papeis.ColaboradorEndUser));
//cria papel padrao para cada novo inscrito = Cliente
await _userManager.AddToRoleAsync(user, Papeis.ClienteEndUser);
//ENVIA EMAILS SE NECESSARIO (ISSO PODE ESTAR NA SUA CAMPANHA, MANDANDO E-MAILS BONITOS E RESPONSIVOS)
await _emailService.SendEmailAsync(Input.Email, "Confirme seu e-mail no Poupatempo Digital",
$"<h4><b>Por favor confime sua conta</b> <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicando aqui.</a>.</h4><h5> Obrigado. Confirmando sua conta, você já terá acesso à sua <b>Agenda Inteligente</b> de Tarefas. Você vai curtir!<h5>", "Html");
var mensagem = "O usuário " + Input.FirstName + " " + Input.LastName + "e-mail: " + Input.Email + "Telefone: " + Input.PhoneNumber + " acabou de abrir conta no Poupatempo Digital";
var assunto = "o usuário " + Input.FirstName + " " + Input.LastName + " acabou de entrar no Poupatempo Digital";
var destino = "xxxxx@clickstobricks.com";
await _emailService.SendEmailAsync(destino, assunto, mensagem, "Text");
Pronto, é isso. Registre um novo usuário com sufixo mailinator.com
Exemplo: maria@mailinator.com
Acesse https://mailinator.com
Digite maria e dê enter. Se você definiu que o primeiro e-mail de sua campanha é enviado imediatamente após a inscrição do e-mail na lista, Maria já terá recebido seu primeiro e-mail .
Não se esqueça de ter a chave de sua API SendGrid no arquivo appsettings.json, conforme modelo abaixo.
chave secreta da API da SENDGRID, no arquivo appsettings.json
"UserPassword": "xxxxxxxxxxxxxxxxxxxxxxxx"
"ApiKey": "xptodfde7WI5ZzpMinesA.blm98jwSobPj1enFAd2a7kQQrAYULi0-csraFJ0NzRs" //poupatempo digital 09/01 full access
"accountSid": "ACewrewrwere1b43d312b7601",
"authToken": "1710ewerewrewrw6c0f589b968cfc5",
"whatsAppFrom": "whatsapp:+14155238886" //número de saída Twilio
"chaveDeSite": "6Le0jCQaAAAAAHMSbanWiWoZrewrewrewGB4FWZET",
"chaveSecreta": "6Le0jCQaAAAAAPSNwZeRYywrewrwerwe8wSUSj"
"DefaultConnection": "Data Source=SQL.site.net;Initial Catalog=DB_A2A240;User Id=DB_user;Password=password;;Connect Timeout=20000;"
Referências que vão de ajudar
API Sendkey, como obter e usar
Guia de Parametrização para enviar e-mails pelo SendGrid
Documentação completa, com exemplos – inclusive c#, da API SendGrid V3 (tipo: tudo o que você pode fazer)
Gostou? Deixe sugestões e comentários!
por Alcides Soares Filho | 13/10/2019 | Desenvolvimento de Aplicações, Identidade/Autorização, Menus | 0 Comentários
Muitas vezes você quer pré-definir os papéis (roles) para todos possíveis usuários da sua aplicação, Bem como definir um ou mais usuários com poder administrativo geral, ou também um usuário gerenciador, com menos poderes que o administrador. Este artigo mostra como fazer isso,
Ao rodar o arquivo STARTUP.CS é perfeitamente possível gerar todos os papéis (Roles( desejados para a sua aplicação, bem como definir ao menos um usuário administrativo com superpoderes e outros usuários com menores poderes. Isso vai ajudar, depois, a definir menus seletivos, onde só aparecem opções de navegação a que cada papel (role) dá direito.
Passo 1 – Nova tabela no banco de dados
Parimos do princípio que você já tem seu database com as tabelas que necessita, conforma artigos anteriores, O que vamos precisar agora é de uma nova tabela que contenha o que o menu de cada pape (role( deve conter ou não.. Ou seja, precisamos fazer uma tabela de relacionamento entre a tabela ASP.NET Roles e nossa tabela de menu. Vamos ver em detalhes sobre como criar nossa nova Tabela de Menus que tem um relacionamento com a tabela ASP.NET Identity AspNetRoles. A ess tabela vamos dar o nome MenuMaster, com os seguintes campos:
Tabela MenuMaster – Campos e Descrições
MenuIdentity é o campo de identidade usado como linha de ID (KEY)
MenuID é a identidade propriamente dita usada como referência primárias para qualquer campo do Menu
Parente_MenuID para cada top MenuID será usado o valor "*". Esse valor serpa usado somente para itens de menu com nível igual a 1 (primeira opção por default). Se na hierarquia de menus houver níveis 2 ou 3, elas farão referência ao menu raiz *MenuID", que são pais
User_Rool Cria o menu para cada papel de usuário (User Role). O menu serpa mostrado para os usuários que tem esse papel (role) e que estiverem logados. Por exemplo, Admin pode criar diferentes menus para gerentes, consultores e outros papéis, E somente usuários que tenham esses papéis poderão ver esses menus
MenuFileName Este é o nome real para cada opção do menu (o que aparece em tela). A ideia qui é usar o view nMWdo MV como MenuFileName
MenuURL É o Menu path para cada item do Menu, usado como hiperlink,, Em MVCé o nome do Controlador (controller)
USE_YN Se usado Y, o item de menu vai aparecer, Se usado N, não vai aparecer, mesmo que ateda os requisitos de papel(role), Em geral é controlado por Viewbags, que definem se em certas condições do item de menu deve ou não aparecer,
CreateDate Data de criação do item do Menu
Passo 2- Criando a tabela no banco de dados, antes de popula-la
No arquivo STARTUP.CS, acrescente em services,addIdentity a parte de código relativo a
Se ao compilar o Visual Stdio reclamar que não consegue apagar um diretório na pasta OBJ da aplicação, apague manualmente e recompile novamente,
ARQUIVO STARTUP.CS - acrescente metodo services.ConfigureApplicationCooki
// COPIE A PARTIR DAQUI
//COPIE ATÉ AQUI
Agora vamos criar o modelo com a classe MenuMaster, na pasta Models:
modelo com a classe MenuMaster, na pasta Models:
namespace DiagnosticoCultura.Models
[Display(Name = "Id do Menu (chave)")]
[Display(Name = "Identidade do menu")]
[Display(Name = "Nome de display do Menu")]
[Display(Name = "MenuID do Menu Pai (quando existir)")]
[Display(Name = "Papel (Role) em que o menu está permitido")]
[Display(Name = "Nome da ação DENTRO DO CONTROLLER")]
[Display(Name = "Nome do CONTROLLER")]
[Display(Name = "Mostra Menu (Y-N)")]
//alternativa: colocar no controle yourModel.DataCadastro = DateTime.Now;
[Display(Name = "Data de Criação do Menu")]
public MenuMaster()
Passo 3 – Gerando a tabela MASTERMENU no nosso database
Recompile a aplicação para ver se até aqui não deu qualquer erro. O resultado deve ser:
No Solution Explorer clique na pasta Controllers e com o botão da direita selecione ADD->New Scaffolded Item. Escolha MVC e à direita escolha MVC Controllers with Views, using Entity Framework. Clique no botão ADD.
Em Model Class escolher o modelo MenuMaster , que ai aparecer como MenuMaster (DiagnosticoCultura.Models) . Clique no botão ADD.
Agora vamos Rodar a miração na console PMC:
add-migration mastermenu
Se compilar o programa e digitar https://localhost:44387/MenuMasters você verá que está tudo pronto para cadastrar os menus.
Passo 4 – Criando classes de interface
Agora é hora de criarmos uma interface com um método chamado GetMenuMaster() e outro método chamado GetMenuMaster (String UserRole).
Implementaremos essa interface em nosso serviço para obter todos os detalhes do menu da tabela e também outro método para obter o menu considerando o papel (ROLE) do usuário.
Para criar a interface, adicione uma nova classe à sua pasta de modelos e nomeie a classe como "IMenuMasterService". Vamos mudar a classe para uma interface, pois vamos criar uma interface para implementar em nosso serviço
interface de modelos de menus ARQUIVO IMenuMasterService.CS PASTA mODELS
Passo 5: Criação do Serviço de Menus:
Agora vamos adicionar uma nova pasta de serviços de classe (abrir uma pasta raiz chamada Services) e nomear a classe como "MenuMasterService".
Nesta classe, estaremos implementando nossa interface IMenuMasterService.
Sabemos que, se implementarmos a interface, devemos declarar o método de interface em nossa classe. Neste serviço, usamos o método de interface e retornamos a lista com detalhes do Menu e também retornamos os detalhes do Menu por função do usuário. Depois estaremos injetando isso diretamente em nossa página de visualização.
code snipet Criacaoo do Servco de Menus:folder SERVICER arquivo MenuMasterService.cs
using DiagnosticoCultura.Data;
using DiagnosticoCultura.Models;
namespace DiagnosticoCultura.Services
public class MenuMasterService : IMenuMasterService
return _context.MenuMaster.AsEnumerable();
var result = _context.MenuMaster.Where(m => m.User_Roll == UserRole).ToList();
Passo 6: Registrando o serviço
Precisamos registrar nosso serviço criado no contêiner. Abra o Startup.cs do seu projeto para adicionar o serviço ao contêiner.
Na classe Startup.cs, encontre o método denominado ConfigureServices e adicione seu serviço "MenuMasterService" como abaixo.
Registrando o servico no startup.cs (acrescentar MenuMasterService em ConfigureServices)
// adicionar using DiagnosticoCultura.Services;
//no topo do arquivo startup.cs
Passo 7: Injetando o serviço de menus na página _Layout.cshtml
Agora, é muito mais simples e fácil, já que podemos injetar diretamente o serviço em nossa página de visualização e vincular todo o resultado à nossa página de visualização.
Para injetar o Serviço em nossa Visualização, aqui estaremos usando nossa página _Layout.cshtml existente.
Como vamos exibir o menu no topo do nosso site e usá-lo em todas as nossas páginas, aqui usamos a página _Layout.cshtml para vincular os resultados do menu como um menu baseado no usuário logado.
Aqui primeiro verificamos se o usuário está Autenticado em nosso site. Se o usuário estiver logado, obteremos os detalhes do papel do usuário conectado e vincularemos o menu com base nas funções do usuário.
Aqui no exemplo estamos vinculando 2 nível do menu como Menu Principal e Submenu.
Em nosso resultado de tabela, verificamos todos os Parenut_MenuID = "*", já que estaremos exibindo o menu principal com o parent_MenuID como "*" e no próximo loop interno, exibimos o submenu apropriado para o menu principal.
IMPORTANTE> Faça um backup do _Layout.cshtml ANTES de alterar qualquer coisa, Se
mudancas na pagina _Layout,cshtml (pasta ViewsShared) - veja o que deve ser acrescentado e onde
<title>@ViewData["Title"] - Diagnóstico de Cultura</title>
<link href="https://cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" type="text/css" />
<!-- Essential JS 2 Button's material theme (Control Styles) -->
<link href="https://cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" type="text/css" />
<!-- Essential JS 2 Button's global script (Control Script) -->
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Diagnóstico de Cultura</a>
© 2019 - Diagnóstico de Cultura - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
ASP.NET Core 2.0: User Role Base Dynamic Menu Using Dependency Injection
How can I get the current date in ASP.NET Core MVC?
ASP.NET Core 2.2 – Razor Pages Logout Behavior
Como Criar, Ler, Atualizar e Apagar Usuários com o ASP.NET Core Identity
por Alcides Soares Filho | 22/12/2020 | Desenvolvimento de Aplicações | 0 Comentários
Neste tutorial, realizarei operações CRUD para criar, ler, atualizar e excluir usuários na identidade (Identity) do ASP.NET Core. Antes de continuar, você deve instalar e configurar a identidade do ASP.NET Core em seu projeto – se ainda não instalou.
.NET Core 5.0 SDK ou mais recente;
Visual Studio 2019 versão 16.8 ou posterior com ASP.NET e carga de trabalho de desenvolvimento web… Instale, pelo menos, os seguintes "workloads":
No Visual Studio, selecione File > New > Project e escolha o template conforme a figura abaixo:
Dê um nome para o seu projeto teste como "MVCMovie" (é importante lembrar que ao dar esse nome, se você copiar código daqui, vai ter de trocar o namespace de todas páginas de controle (.cs) para o nome do seu projeto.
Escolha umm local no seu disco para os programas fonte;
Escolha a opção de deixar a solução e o projeto no mesmo diretório.
Escolha a aplicacão e clique em Change, para escolher o tipo de autenticação
Selecione a opção Individual User Accounts e de OK.
Clique em CREATE. Pronto. O projeto está pronto.
O Visual Studio usou um modelo padrão para o projeto MVC que você acabou de criar, já com identidade (Identity instalada).
No lado direito há as opções de registro e login. Você já possui um aplicativo de trabalho inserindo com o nome de projeto, que permite selecionar algumas opções.
Este é um projeto inicial simples e é um bom lugar para começar. No Visual Studio, clique em F5 para executar o aplicativo no modo de depuração ou Ctrl-F5 no modo de não depuração.
Criar novos usuários na identidade (Identity)
Para criar usuários na identidade do ASP.NET Core, você precisará criar uma classe de modelo. Comece tudo criando uma classe chamada AppUser.cs dentro da pasta Models (Modelos). Adicione propriedades públicas a ele, que são, no meu caso:
FirstName, LastName, Email (com override, pois já existe em Identity), PhoneNumber (com override, pois já existe em Identity) e Password, do tipo string. Adicione também atributos de validação de modelo [Required] a eles
FullName (campo calculado FirstName + LastName
Interesse, tipo inteiro, não obrigatório (por isso usei int? – a interrogação torna o campo não obrigatório)
Criando o controlador de todas as operações
Para fazer todas operações de leitura, autalização, criação, deleção – teremos de ter um controlador geral – que vamos incluir na pasta de Controllers (controladores). Vamos dar o nome a esse arquivo controlador de AdminController.cs.
Note que em Create o novo usuário tem variáveis que não existem no arquivo original de Identidade: FirstName, LastName, Interesse e Password. Esses campos serão adicionados à tabela de usuários original do ASP.NET.
O Password = user.Password guardará a password em string, sem afetar a guarda da senha codificada pelo aspnet. Para mim isso é útil, mesmo não sendo seguro. Você pode não incluir essa linha se quiser.
Para o arquivo de pessoas receber os novos campos, entre em Tools, Nuget Package Manager, Package Manager Console e digite:
add-migration Usuarios
Codigo AdminController.cs. na pasta Controllers
private IPasswordHasher<AppUser> _passwordHasher;
UserManager<AppUser> userManager
, ILogger<AdminController> logger
, RoleManager<AppRole> roleManager
, IPasswordHasher<AppUser> passwordHash
_passwordHasher = passwordHash;
List<AppUser> novaListaUsuarios = new List<AppUser>();
var todosUsuarios = (from user in _userManager.Users
ViewBag.DataSource = todosUsuarios;
// GET: Pessoas/Delete/5
var usuario = await _userManager.Users.FirstOrDefaultAsync(m => m.Id == id);
//ViewBag.DataSource =  _userManager.Users;
AppUser user = await _userManager.FindByIdAsync(id.ToString());
IdentityResult result = await _userManager.DeleteAsync(user);
{ return RedirectToAction(nameof(Index)); }
{ Errors(result); }
ModelState.AddModelError("", "Usuário não Encontado");
//return View("Index", _userManager.Users);
//ViewBag.DataSource = _userManager.Users;
public async Task<IActionResult> Update(int Id, string email, string password, string FirstName, string LastName, string PhoneNumber)
ModelState.AddModelError("", "O E-mail não pode ser vazio");
ModelState.AddModelError("", "O Nome não pode ser vazio");
ModelState.AddModelError("", "O Sobrenome não pode ser vazio");
ModelState.AddModelError("", "O telefone do WhatsApp não pode ser vazio");
user.PasswordHash = _passwordHasher.HashPassword(user, password);
ModelState.AddModelError("", "A senha não pode ser vazia");
ModelState.AddModelError("", "Usuário não encontrado");
public async Task<IActionResult> Create(AppUser user)
var usuario = await _userManager.FindByEmailAsync(user.Email);
if (usuario != null) //existe usuario
ModelState.AddModelError("Email", "Este e-mail já está cadastrado no PoupaTempo. Entre no sistema usando o Acesso, no menu");
Interesse = 4, //todo definido um valor fixo arbitrário, deveria ser  user.Interesse,
appUser.UserName = appUser.Email;
appUser.EmailConfirmed = true;
//appUser.SecurityStamp = Guid.NewGuid().ToString();
IdentityResult result = await _userManager.CreateAsync(appUser, user.Password);
await _userManager.AddToRoleAsync(appUser, Papeis.ClienteEndUser);
ModelState.AddModelError("Erro:", error.Description);
Note que ao adicionar um usuário:
testo para ver se esse e-mail já não cadastrado anteriormente;
associo a ele uma "role", ou seja, um papel. No meu caso:
testo se os 3 papeis que uso (cliente, colaborador e administrador) já existem no arquivo de roles. Se não existem, são criados;
associo o usuário adicionado uma role padrão, no meu caso, cliente.
O arquivo de roles (papeis, que você pode mudar) fica na pasta models, em papeis.cs
Criando as Views (visualizações)
View de criação
Arquivo Create.cshtml. Pasta Views-&amp;amp;amp;amp;amp;gt;Admin
@model PoupaTempoDigital.Models.AppUser
ViewData["Title"] = "Cria Usuário";
<h1 class="bg-info text-white">&nbspCria Novo Usuário</h1>
<a asp-action="Index" class="btn btn-secondary">Retornar</a>
<input asp-for="Email" autocomplete="off" class="form-control" />
<span asp-validation-for="Password" autocomplete="off"  class="text-danger"></span>
View de Atualização
Arquivo Update.cshtml. Pasta Views-&amp;amp;amp;amp;amp;gt;Admin
ViewData["Title"] = "Atualiza Usuário";
<h1 class="bg-info text-white">&nbspAtualiza Usuário</h1>
Listagem dos usuários
Para a listagem eu usos pacotes da Syncfusion, que me facilitam muito a paginação, o sort e a pesquisa em cada campo mostrado (veja meu artigo Syncfusion Core: acelerando o seu desenvolvimento em Core MVC com componentes).
Nessa página de listagem eu inclui dois botoes, um de atualização e outro para apagar o usuário. Seria bobagem gerar uma segunda listagem só para escolher o usuário a ser "apagado".
Esses dois botões são construidos dentro do "template" logo abaixo do grid, entre <script> e </script>.
De qualquer forma deixei comentado o "código tradicional" para este tipo de view, caso não queira usar o Syncfusion. Não tem paginação, nem sort, nem nada, como de hábito.
No topo da página acrescentei um botão para a criação de novos usuários.
Arquivo Index.cshtml. Pasta Views-&amp;amp;amp;amp;amp;gt;Admin
@model IEnumerable<PoupaTempoDigital.Models.AppUser>
ViewData["Title"] = "Listagem de Usuários";
<h1 class="bg-info text-white">&nbspTodos os Usuários</h1>
<a asp-action="Create" class="btn btn-secondary">Cria Novo Usuário</a>
<ejs-grid id="Grid" locale="pt-BR" dataSource="@ViewBag.DataSource" allowPaging="true" allowSorting="true" allowFiltering="true" allowGrouping="true" gridLines="Both">
<e-grid-column field="Id" headerText="Id" isPrimaryKey="true" isIdentity="true" width="50"></e-grid-column>
<e-grid-column field="FullName" headerText="Nome" textAlign="Left" width="120"></e-grid-column>
<e-grid-column field="PhoneNumber" headerText="WhatsApp" width="100"></e-grid-column>
<e-grid-column field="Email" headerText="E-mail" width="150"></e-grid-column>
<e-grid-column field="" headerText="Ação" width="130" textAlign="Center" template="#template"></e-grid-column>
@*<a rel='nofollow' href="/Pessoas/Edit/${Id}">${NomeCompleto}</a>*@
<a rel='nofollow'  class="btn btn-sm btn-primary text-white" href="/Admin/Update/${Id}">
<a rel='nofollow'  class="btn btn-sm btn-warning text-white" href="/Admin/Delete/${Id}">
@*<table class="table table-sm table-bordered">
<td>@user.PhoneNumber</td>
Tela para Apagar Usuário
Não tem tela para apagar e sim uma tela de confirmação, caso acidentalmente seja clicado o botão "Apagar".