Já parou para pensar que tudo na vida é um evento?
Alguns diriam “sim, já pensei nisso…”, outros “sinceramente não… ”. Não estou dizendo um evento festivo apenas, mas sim fatos que ocorrem todos os dias na nossa vida.
Hoje vou trazer alguns eventos que fizeram eu iniciar na tecnologia e que contribuem para que eu permaneça por bastante tempo colaborando em projetos de diversos nichos diferentes.
Iniciando com o Asp.Net Boilerplate — Felipe de Almeida
Framework de Aplicações Web — Uma forte infraestrutura para aplicações web modernas
Há alguns anos recebi um desafio de um ex-professor, mentor e padrinho de casamento. Antes de falar do desafio é importante saber que o Sergio Brugnolo já foi meu professor no ensino médio (2007) e no técnico (2008–2009) pela Etec, e na faculdade (2009–2013) onde ele era Professor e Coordenador do Curso de Sistemas de Informação. Além disso, recentemente foi meu padrinho de casamento (que aconteceu só no civil por enquanto, por causa da pandemia).
O Desafio
O desafio foi criar rapidamente um aplicativo para um evento que aconteceria nos próximos meses, era o Geek Etec 2018. Então utilizei um Boilerplate para acelerar o processo de desenvolvimento do back-end e do front-end do portal que seria o painel administrativo do administrador do evento, que tinha o Sergio e outras pessoas que estavam organizando o evento também.
Este projeto está no GitHub:
· Eventcloud (Asp.Net Boilerplate Template com Angular e dotnet core)
· Ionic Conference App (Template de App e PWA em Ionic usando Angular e Cordova)
Aplicação Hibrida Multiplataforma
Hoje não vou abordar muitos detalhes do Ionic, que é um framework no qual comecei a ter contato em 2015 e desenvolvi alguns projetos legais, como este para o setor agropecuário que recebi este feedback em outubro de 2016:
Framework de Aplicações Web
O projeto do Eventcloud está desatualizado e quero abordar aqui um passo a passo do que seria a nova versão do Think Event, que foi o nome que dei para a plataforma de eventos em 2018, que era um fork do Eventcloud, um template feito com Asp.Net Boilerplate.
Essa plataforma se fosse criada hoje teria algumas mudanças, já que os eventos estão acontecendo online por conta da Pandemia. Então vamos cria-la seguindo um passo a passo prático, onde vou aproveitar para explicar alguns recursos interessantes da arquitetura do Asp.Net Boilerplate que segue todas as boas práticas exigidas no mercado e um pouco mais.
Arquitetura Moderna
Antes de colocar a mão na massa, um pouco da arquitetura do Asp.Net Boilerplate que é uma estrutura que usa ferramentas já conhecidas e implementa as melhores práticas em torno delas para fornecer ao time uma experiência de desenvolvimento SOLID.
· Arquitetura em Camadas
o Fornece um modelo de arquitetura em camadas (NLayer Architecture) com base em Domain Driven Design
· Multi Tenancy — Aplicações SaaS mais fáceis! Multi-tenancy integrado por uma interface de usuário amigável até um banco de dados completo usando MSSQLServer.
· Bem Documentado — Documentação abrangente e tutoriais de início rápido.
· Design Modular — Projetado como modular e extensível. Fornece infraestrutura para construir seus próprios módulos também.
· Design Orientado por Domínio — Projetado e desenvolvido com base no DDD. Fornece um modelo SOLID para sua aplicação.
· Livre de código aberto — Desenvolvido ativamente no GitHub (licença MIT) e aberto para contribuições.
Como Funciona
Não precisa ficar repetindo código! O Asp.Net Boilerplate automatiza tarefas comuns de desenvolvimento por convenção. Assim nos concentramos somente no código da camada de negócio.
Modelos de Inicialização
Podemos criar nossa solução com um pontapé inicial que pode ser mais enxuto e gratuito ou mais completo e premium. Podendo selecionar entre projetos com SPA (Angular, React ou Vue.JS) ou uma arquitetura MVC clássica que usa jQuery.
Neste caso vamos a página de templates e iniciar uma plataforma grátis com o template utilizando angular, .Net 5 e banco de dados MSSQLServer:
Download do Template
Se preenchemos tudo corretamente e clicamos no botão para criar o projeto, teremos o download de um zip contendo a aplicação do Front-End e do Back-End:
Ao extrair o zip temos uma pasta com a versão do template, no meu caso é a 6.3.0 e dentro desta pasta teremos dois projetos (angular e aspnet-core), screenshots, arquivos de configuração do Git, licença, o README.md e um script caso você queira renomear a namespace da solução:
Repositório no GitHub
Criei dentro da conta da Think A.M. no GitHub um repositório chamado Think Event, nele estou subindo este Boilerplate que foi gerado e caso queira contribuir com o projeto, é a partir deste repositório que faremos o Fork para depois criarmos nosso PR (Pull Request) com a contribuição.
Caso você não tenha familiaridade com este tipo de assunto, entre para a comunidade da Think A.M. no Discord que lá nós direcionamos você para os conteúdos que você deve acessar para entender esses termos e processos para destravar sua jornada como dev.
O MVP
Para fins de estudo das tecnologias vamos criar uma aplicação que poderá ser usada por empresas e comunidades nos eventos online. Nela teremos as seguintes funcionalidades:
· Criar Organização, que pode ser:
- Uma empresa que tem centenas de funcionários e quer alinhar o conhecimento de todos;
- Ou uma comunidade com o objetivo de compartilhar conhecimento de uma tecnologia ou de um grupo de pessoas que estão buscando por informações do mesmo assunto.
· Dentro da organização podemos criar Eventos, que terão:
- Informações básicas do evento
- § título (exemplo: Workshop da Firma)
- § descrição (exemplo: Conte para os colegas o que vem aprendendo)
- § foto (exemplo: A turma da firma reunida no último churrasco)
- § data do evento
- § plataforma (exemplo: Google Meet, Zoom ou Teams)
· Dentro do Evento teremos:
- Speakers, que são os apresentadores
- Categorias, que podem ser os temas abordados
- Sessions, detalhes das apresentações com preview do que vai ser falado
- Opção de compartilhamento do evento
- Anexos das apresentações
- Link para a sala da apresentação
- Link para a gravação da apresentação
- Status do Evento (Planejado, em andamento, concluído ou cancelado)
O Projeto
Vamos incluir outras plataformas além dessas mais conhecidas e a opção do presencial para o pós-pandemia. Terá também opções de apoio para eventos gratuitos e compra de acesso nos eventos que são pagos. Além disso a opção de assinar um evento que ocorre com uma certa recorrência, por exemplo, um evento anual que pode ser pago mensalmente em leves parcelas.
Cada Organização tem acesso a painéis por evento que contém informações referente as Sessions e aos participantes que estarão presentes durante as apresentações, quando o evento estiver ocorrendo será possível acompanhar em tempo real os apoios que serão feitos ao evento, anunciar produtos e serviços em chat para que seja feita uma compra, e integração com o PIX no Brasil para pagamentos instantâneos e cartões de crédito em caso de parcelamento em tickets mais altos.
Para eventos que já ocorreram será possível enviar certificado de presença para aqueles que fizeram check-in no evento e ter acesso a todas as informações em formato de relatório com gráficos e tabelas que representam a história do evento.
Tudo isso e um pouco mais está sendo cadastrado na aba de projetos no Repo do GitHub.
Primeira Execução do Template
Vamos utilizar o Visual Studio Code para executar tanto o Back-End quando o Front-End da aplicação, veremos a seguir que através dele conseguimos ter bastante produtividade.
Logo que abrimos a pasta do aspnet-core com o VSCode ele já sugere a instalação da extensão de C#:
No menu Explorer do VSCode podemos visualizar a aplicação e suas camadas (Web.Host, EntityFrameworkCore, Core e Application) que serão as camadas que realmente teremos que alterar algo para trabalharmos nesse objetivo do projeto.
Começaremos pela camada ThinkAM.ThinkEvent.Web.Host, ou para os íntimos, somente Web.Host. Nela confirmaremos o nosso appsettings.json:
Nele podemos notar que precisamos de um servidor localhost do MSSQLServer que irá conectar automaticamente com o usuário do Sistema Operacional, que no meu caso é Windows e o nome do banco de dados, que ainda não existe, porém com um comando será gerado automaticamente pelo nosso projeto que usa Entity Framework Core (EFCore).
Se você possui as configurações do banco de dados de acordo com a realidade da sua máquina, ou seja, você tem o MSSQLServer instalado e pode fazer login com o mesmo usuário do seu sistema operacional, prossiga para o próximo passo, caso contrário altere para uma configuração que você consiga autenticar com o banco de dados.
Tudo certo? Vamos clicar com o botão direito do mouse ou rato em Portugal, acima da pasta EntityFrameworkCore e escolher a opção Open in Integrated Terminal:
Caso sua aplicação esteja com as pastas todas vermelhas como aparece na imagem, não se assuste! É porque ainda não restauramos as dependências do projeto.
Se você já possui o dotnet instalado e o dotnet-ef, basta executar o seguinte comando no terminal:
dotnet ef database update
Caso você não tenha o dotnet-ef instalado, irá aparecer o seguinte aviso:
Para resolver este problema é simples, basta executar o seguinte comando:
dotnet tool install --global dotnet-ef
Agora se executamos novamente o comando que havia dado erro, ele executa com êxito, caso tenha algo de errado com a sua conexão com o banco de dados aparecerá o seguinte problema:
A falha no logon de usuário pode ser resolvida alterando a conexão para o localdb da Microsoft que é instalado junto com o Visual Studio.
Ao abrir o VS podemos ir em Exibir > SQL Server Object Explorer e depois adicionar um novo servidor, aparecerá uma janela que poderá ser fechada, pois terá sido criada uma instância do localdb nesse momento que ainda não terá nenhum banco de dados nela:
Agora nosso appsetings.json ficou assim:
Após salvar a alteração é só executar o comando que havia dado erro que agora estará funcionado perfeitamente:
Note que existem migrations desde 24/04/2017 e vão até 24/03/2021. Essas migrations são muitas vezes agrupadas em uma única migration entre uma versão e outra, portanto já existiram migrations mais antigas que 2017 neste projeto.
CRUD de Organização
Existem estruturas que foram criadas durante as migrations executadas no passo anterior, dentre elas temos AbpOrganizationUnits que são basicamente unidades organizacionais do Asp.Net Boilerplate, na versão premium da solução teríamos essa tabela sendo implementada para através dela gerenciarmos perfis e permissões específicas por hierarquia organizacional.
Caso nossa aplicação cresça essa tabela será fundamental para o projeto, portanto o meu CRUD de Organização (AppOrganizations) terá um relacionamento com essa tabela através da intermediação da entidade Workspaces.
Como já temos uma aplicação Multi-tenancy, cada Tenant será então um evento e assim já teremos nativamente, só de usar o template como base, uma separação da informação por evento, ou seja, a pessoa que é participante de um evento não enxerga informações de outro evento que não está vinculado.
A organização poderá ter vários eventos, portanto terá no cadastro da organização qual será o tipo de organização (Comunidade, Empresa, Grupo Musical, Podcast etc.), e qual será a moeda da organização, por exemplo, se for Real será possível utilizar o Pix e o PagSeguro como integrações possíveis de serem feitas.
De forma prática vamos criar a seguinte estrutura para o CRUD de Organização:
Mas antes precisamos criar o CRUD de Tipos de Organização (AppOrganizationTypes):
Para isso seguiremos um fluxo, no qual desenhei pensando já na versão Premium do Asp.Net Zero, porém serve também para a nossa versão Free e Open Source:
Extensão do VSCode
Antes de iniciar a jornada prática do CRUD eu recomendo que baixe uma extensão para o VSCode que preparei há poucos meses:
Após instalada a extensão, vamos criar uma pasta na camada ThinkAM.ThinkEvent.Core, ou para os íntimos, simplemente Core:
Dentro da nova pasta vamos criar com auxílio da extensão uma nova classe C#:
Ao digitar OrganizationType na caixa de texto que apareceu no topo da janela e pressionar Enter:
Notamos que foi criado um arquivo com o nome que escolhemos e no Namaspace que estamos posicionados, para fins de organização das etapas seguintes, vamos começar removendo o .Core do namespace e mais a frente irei explicar a linha de raciocínio para essa decisão.
Daremos na sequência um nome para ser criada a tabela no MSSQLServer e faremos utilizando herança a inclusão de colunas para que os dados dessa tabela sejam “auditados” caso necessário:
Percebemos na imagem acima que além de acrescentar “[Table(“AppOrganizationTypes”)]” como uma data annotation acima da class e o “: FullAuditedEntity” para que seja feita a herança, o próprio VSCode sugere na lâmpada amarela o uso de referências a bibliotecas que já estão inclusas no projeto. Essa sugestão acontece graças a extensão que adicionamos lá no início que é do C#.
Se adicionamos a biblioteca sugerida e posicionarmos o cursor agora em Table que é a class ainda sem referência, teremos a opção de mostrar novas dicas para resolver o problema:
Ao selecionar a opção sugerida, assim como já foi feito antes, a extensão adicionará automaticamente a referência necessária acima do Namespace:
Ficando assim a class sinalizada em verde como algo que está “ok”:
Agora vou incluir os atributos que havia planejado para essa entidade na Issue do GitHub:
Ao colocar em FullAuditedEntity entre o sinal de menor e maior o tipo int eu já estou definindo o Id como inteiro, e dentro da class se eu digito “prop” o visual studio code me sugere um code snippet que cria um modelo de propriedade C# com get e set, vamos coloca-la como tipo string na primeira seleção que é feita automaticamente e dar um TAB para digitar o nome “Name” na segunda seleção e ficando assim:
Note que ao dar o “ctrl + s” no final eu consigo salvar as mudanças do arquivo.
Vamos adicionar um limite de 50 caracteres na propriedade Name:
Como forma de deixar um código mais legível e de fácil reuso em passos seguintes, criamos uma constante para o máximo de caracteres que é feito através de uma data annotation chamada StringLength.
De acordo com o passo a passo que havia colocado aqui antes, acabamos de seguir as três etapas da camada Core:
Agora vamos adicionar o nosso DbSet no nosso contexto da aplicação:
Essa outra camada é a camada da nossa EFCore, nela temos todas as configurações referente ao mapeamento das classes de entidade com o nosso banco de dados, que neste caso é o MSSQLServer, mas que poderia ser outro banco de dados como por exemplo o PostgreSQL.
Portanto acessaremos em ThinkAM.ThinkEvent.EntityFrameworkCore a pasta EntityFrameworkCore e a class ThinkEventDbContext que terá um comentário instruindo o local onde deverá ser criado o DbSet que precisamos:
Adicionamos o DbSet e percebemos que temos algumas referências utilizadas na herança deste contexto que nos fez já ter uma série de entidades criadas quando executamos as migrations que já vieram com o projeto:
Note que da mesma maneira que Organizations, temos outras referências que repetem o mesmo início de namespace “ThinkAM.ThinkEvent”, sendo assim vamos mover para dentro do namespace essas referências, assim sabemos quais referências são de dentro da solução e evitamos problemas de conflitos de nome com referências externas.
Veja também que no DbSet que foi criado nós colocamos o nome do atributo no pural:
Nesse momento poderemos passar para a próxima etapa do processo de criação do CRUD:
Na versão Premium da arquitetura essas duas camadas são o que na versão Free é apenas a camada Application, ou seja, vamos criar a Interface, DTO’s e Application Class na camada Application com o auxílio da nossa Extensão do VSCode que já traz um code snippet para facilitar nossa vida.
Para criação dos arquivos precisamos antes criar a nossa pasta Organizations também na camada Application:
Após criada a pasta podemos clicar com o botão direito do mouse em cima da pasta e escolher a opção “New C# Interface App Service”:
Depois disso é só escolher o nome do arquivo, como é uma interface colocamos a letra i em maiúsculo no início e fica assim:
Após pressionar a tecla Enter temos um resultado que terá alguns ajustes, como namespace e a necessidade de criar a etapa que envolve os DTO’s:
Retiramos a namespace .Application e criamos dentro de Organizations a pasta Dto para criarmos nosso primeiro Dto usando a nossa extensão:
Digitamos o nome da class que será CreateOrganizationTypeDto:
Ao retirar também o Namespace .Application teremos a dependência da nossa Entity Class resolvida automaticamente:
Na sequência poderemos copiar e colar os mesmos atributos e data annotations da Entity Class, que neste caso é apenas Name:
Agora que já resolvemos a dependência podemos colocar o atributo MaxNameLength sendo um atributo da nossa Entity Class:
Agora para resolver os outros problemas desta class somente mais a frente quando restaurarmos as nossas dependências.
Antes de restaurarmos as dependências da solução, vamos criar mais um Dto, agora será na opção “New C# Dto Class”:
Fizemos praticamente as mesmas mudanças de namespace e atributos, porém agora também temos o detalhe do tipo da primary key da nossa entidade que é do tipo int:
Para finalizar o CRUD na API de tipo de organização agora é só criar na pasta Organizations na camada Application a AppService em “New C# Class AppService”:
Pronto! Criamos a class OrganizationTypeAppService, ajustamos o namespace e agora será somente restaurar os pacotes:
Para resolver isto vamos na opção “View > Terminal” ou então pelo atalho do seu VSCode que dependerá de qual sistema operacional você está:
Com o termina aberto digitaremos “dotnet restore”:
Após executado o dotnet restore teremos uma saída parecida como essa no seu terminal:
No template gerado do AppService virá como Guid em alguns lugares, devemos alterar para int que é o tipo da nossa primary key nesta entidade, com isso alteramos na classe e na interface:
No caso da linha 12 é até desnecessário, já que não iremos ter neste caso nenhum método implementado além do CRUD, ficando assim:
No final do ajuste teremos tudo verde:
Agora retomando a nossa sequência do processo de criação do CRUD que documentamos no Whimsical, é só rodar a aplicação:
Para isso vamos abrir um terminal integrado no diretório ThinkAM.ThinkEvent.Web.Host, ou simplesmente para os íntimos, no diretório Web.Host:
Podemos fazer o build através do comando “dotnet build”:
E por fim pressionar F5 no VSCode que perguntará qual será o projeto de inicialização, caso ele peça para adicionar a extensão C# novamente, faça o fechamento do VSCode e a abertura novamente, pois algumas funções da extensão só são realmente aplicadas após pelo menos uma reinicialização do editor com a extensão, e se for a sua primeira execução com ela no VSCode não irá aplicar a essa mudança, após reiniciar aparecerá algo assim que podemos escolher Yes, ou seja, queremos ativar o modo Debug do projeto:
Feito isso ele irá perguntar no topo da página qual é então o projeto que vamos usar como projeto de inicialização:
Caso você perca essa janela por ter clicado fora, é só pressionar novamente F5 e selecionar o projeto Web.Host, caso seu VSCode não esteja funcionando de acordo com o esperado ele sempre questionará novamente se deseja ativar o build e debug quando reiniciar a janela, feito assim todo o processo ele gerará para você um arquivo em .vscode/launch.json:
Isso é feito através da extensão C#, então em caso de falhas é só fazer manualmente esse processo.
Agora que já temos tudo configurado é só pressionar F5 novamente que dessa vez será executada a aplicação:
Abrirá automaticamente uma janela com o seu browser padrão com uma tela parecida com esta que contém o Swagger configurado:
Notamos que já é possível usar a opção de autorização para métodos que requer permissão específica e percebemos o CRUD que acabamos de construir, que nesse momento ainda não requer autorização, mas vamos acrescentar antes de finalizar essa primeira parte da série de textos tutoriais demonstrando opções do Asp.Net Boilerplate e construindo uma solução totalmente a partir da versão Open Source do Framework.
Mas antes de poder criar o nosso primeiro registro, existe um detalhe muito importante! Que é a criação da nossa primeira migration e assim criar a nossa tabela no banco de dados:
Isso poderia ser feito há algumas etapas, mas vamos dar STOP no nosso debug, pressionar ENTER no terminal para interromper o programa e executar esse passo:
Feito o STOP da execução e de DEBUG, vamos abrir um novo terminal, porém agora na camada EntityFrameworkCore:
No terminal aberto na pasta desta camada vamos executar o comando que adiciona uma nova migração, adicionando a nova tabela que inserimos no contexto no início do nosso texto, utilizaremos o comando dotnet ef migrations add “Added_OrganizationTypes”
Após a execução do comando teremos algo assim como retorno:
Em um dos avisos percebemos que existe a possibilidade de remover a migration que acabamos de gerar se caso identificarmos algum problema antes de realmente aplica-la no banco de dados, por isso vamos conferir nesta mesma camada da EFCore (acrônimo para Entity Framework Core) a pasta Migrations que contém dois arquivos:
É importante conferirmos o primeiro que é o Added_OrganizationTypes.cs:
Ao conferir percebemos que no método Up, que é quando fazemos o database update sem nenhum parâmetro, encontramos a criação da tabela com a propriedade Name que adicionamos na Entity Class e mais outras propriedades que são fruto da herança FullAuditedEntity<int>, por isso nosso Id é do tipo Int, além disso há colunas que são importantes se houver a necessidade de auditar a informação, ou seja, quem criou e quando criou, quem editou e quando editou, quem removeu e quando removeu. Já no método Down é para quando fazemos o database update especificando uma migration que ficou para trás, temos o DropTable, pois é o inverso da criação da tabela do método Up.
Está tudo certo, então vamos aplicar a migration digitando na mesma camada da EFCore o comando dotnet ef database update:
Feito isso agora podemos executar a aplicação e testar o CRUD de tipos de organização:
Agora vamos subir para o GitHub fazendo nosso Commit e depois Push com o auxílio do VSCode e no próximo post continuamos com mais CRUDs, Permissões e a primeira execução do Front-End em Angular.
Por hoje é só, até a próxima!