├── .gitignore
├── aspnet-refit2
└── images
│ ├── swagger1.png
│ ├── swagger1post.png
│ ├── swagger3get.png
│ └── swagger3post.png
├── como-tirar-duvidas
├── images
│ ├── 001.png
│ ├── 002.png
│ ├── 003.png
│ ├── 004.png
│ ├── 005.png
│ ├── 006.png
│ ├── 007.png
│ ├── 008.png
│ ├── banner.jpg
│ ├── share.png
│ └── start-new-discussion.png
└── index.md
├── csharp-implicit-operators
└── .DS_Store
├── csharp-paralelismo
└── images
│ ├── saida1.png
│ └── saida2.png
├── inversion-of-control
└── images
│ ├── share.png
│ └── banner.jpg
├── aspnet-health-check
└── images
│ ├── request1.png
│ ├── request2.png
│ ├── request3.png
│ ├── baltaLogo.png
│ ├── baltaLogo2.png
│ ├── dashboard1.png
│ ├── dashboard2.png
│ └── dashboard3.png
├── blazor-render-modes
└── images
│ ├── Untitled.png
│ ├── Untitled_1.png
│ ├── Untitled_10.png
│ ├── Untitled_11.png
│ ├── Untitled_12.png
│ ├── Untitled_13.png
│ ├── Untitled_14.png
│ ├── Untitled_2.png
│ ├── Untitled_3.png
│ ├── Untitled_4.png
│ ├── Untitled_5.png
│ ├── Untitled_6.png
│ ├── Untitled_7.png
│ ├── Untitled_8.png
│ ├── Untitled_9.png
│ ├── Screenshot_2023-10-18_at_08.28.33.png
│ ├── Screenshot_2023-10-18_at_08.34.42.png
│ ├── Screenshot_2023-10-18_at_08.40.28.png
│ ├── Screenshot_2023-10-18_at_08.40.38.png
│ ├── Screenshot_2023-10-18_at_08.41.00.png
│ ├── Screenshot_2023-10-18_at_08.59.03.png
│ ├── Screenshot_2023-10-18_at_09.17.01.png
│ ├── Screenshot_2023-10-18_at_09.17.17.png
│ └── Screenshot_2023-10-18_at_09.17.31.png
├── blazor-rotas-navegacao
└── images
│ ├── Untitled.png
│ ├── Untitled 1.png
│ ├── Untitled 2.png
│ └── Untitled 3.png
├── aspnet-async-streaming
├── images
│ └── asyncenum.gif
└── index.md
├── dependency-inversion-principle
├── images
│ ├── share.png
│ └── banner.jpg
└── index.md
├── minimal-apis-especificar-porta
├── images
│ ├── share.png
│ └── banner.jpg
└── index.md
├── o-futuro-do-aspnet-e-blazor
└── images
│ ├── Untitled.png
│ ├── Untitled_1.png
│ ├── Untitled_2.png
│ ├── Untitled_3.png
│ ├── spa_drawio.png
│ └── Untitled_Diagram_drawio.png
├── o-que-e-autenticacao-e-autorizacao
└── Untitled.png
├── documentacao-com-github
└── images
│ ├── image-example.jpg
│ ├── table-example.jpg
│ ├── wiki-repo-item.jpg
│ ├── accordion-example.jpg
│ ├── clean-wiki-page.jpg
│ ├── discussion-page.jpg
│ ├── first-structure.jpg
│ ├── second-structure.jpg
│ ├── bad-readme-example.jpg
│ ├── wiki-example-result.jpg
│ ├── wiki-final-summary.jpg
│ ├── discussion-feature-option.jpg
│ ├── added-statistics-to-structure.jpg
│ └── way-to-discussion-feature-option.jpg
├── gestao-de-equipes-com-github
└── images
│ ├── team-page.jpg
│ ├── create-team-form.jpg
│ ├── team-members-page.jpg
│ ├── create-team-button.jpg
│ ├── creating-by-organization.jpg
│ └── link-repository-to-team.jpg
├── git-por-dentro-do-encanamento
└── images
│ ├── image-1.png
│ ├── image-2.png
│ ├── image-3.png
│ └── image-4.png
├── o-que-e-jwt
├── Screenshot_2023-05-16_at_12.41.01.png
├── Screenshot_2023-05-16_at_12.53.34.png
└── Screenshot_2023-05-16_at_12.56.00.png
├── addtransient-addscoped-addsingleton
└── images
│ ├── share.png
│ └── banner.jpg
├── testes-de-mutacao-stryke-dotnet
└── Images
│ ├── img-final.png
│ ├── img-url.png
│ ├── img-killed.png
│ ├── img-testes.png
│ ├── img-mutantes.png
│ ├── img-survived.png
│ └── img-stryker-cli.png
├── hospedagem-gratuita-com-github
├── images
│ ├── deploy-page.jpg
│ ├── pages-option.jpg
│ ├── result-page.jpg
│ ├── pages-settings.jpg
│ └── organization-settings.jpg
└── index.md
├── gestao-de-organizacoes-com-github
└── images
│ ├── people-page.jpg
│ ├── person-page.jpg
│ ├── organization-menu-settings.jpg
│ └── organization-menu-moderation.jpg
├── gestao-de-projetos-com-github
└── images
│ ├── manual-activity.jpg
│ ├── add-new-item-option.jpg
│ ├── change-issue-status.jpg
│ ├── edit-values-of-status.jpg
│ ├── link-issue-with-project.jpg
│ ├── selecting-project-style.jpg
│ ├── creating-project-team-menu.jpg
│ ├── creating-project-user-menu.jpg
│ ├── save-changes-on-project-view.jpg
│ ├── creating-an-issue-on-repository.jpg
│ ├── result-of-new-repository-column.jpg
│ ├── unsaved-changes-on-project-view.jpg
│ ├── add-repository-column-to-project.jpg
│ ├── creating-project-repository-menu.jpg
│ ├── creating-project-organization-menu.jpg
│ ├── saving-changes-of-edition-values-of-status.jpg
│ └── result-of-save-changes-of-edition-of-status-values.jpg
├── utilizando-discord-repositorio-log-dotnet
├── .vs
│ ├── VSWorkspaceState.json
│ ├── slnx.sqlite
│ └── utilizando-discord-repositorio-log-dotnet
│ │ ├── project-colors.json
│ │ └── v17
│ │ └── .suo
└── images
│ ├── img-swagger-1.png
│ ├── img-swagger-2.png
│ ├── img-swagger-3.png
│ ├── img-info-discord.png
│ ├── img-criando-webhook.png
│ ├── img-info-discord-2.png
│ └── img-solution-projeto.png
├── como-testar-o-dotnet-8-e-csharp-12-hoje-mesmo
├── images
│ └── 01.png
└── index.md
├── razor-pages-asp-net-core-qrcode
└── images
│ ├── render-qrcode-1.png
│ ├── render-qrcode-2.png
│ └── render-qrcode-3.png
├── sqlserver-conhecendo-os-cursores
└── images
│ ├── end-table-state.jpg
│ └── first-table-state.jpg
├── criando-api-zero-dotnet-core-3-1-ef-core
└── images
│ ├── Untitled 1.png
│ ├── Untitled 2.png
│ ├── Untitled 3.png
│ ├── Untitled 4.png
│ ├── Untitled 5.png
│ ├── Untitled 6.png
│ ├── Untitled 7.png
│ ├── Untitled 8.png
│ ├── Untitled.png
│ ├── criando-api-zero-dotnet-core-3-1-ef-core_icon.jpg
│ ├── criando-api-zero-dotnet-core-3-1-ef-core_banner.jpg
│ └── criando-api-zero-dotnet-core-3-1-ef-core_share.jpg
├── migrations-efcore-dotnet-postgresql
└── images
│ └── marianarizzo.jpeg
├── criando-projetos-dotnet-via-console
└── images
│ └── dotnet-sdks-list.png
├── criando-workflows-reutilizaveis-github-actions
└── images
│ ├── ci-cd.png
│ ├── repositories.png
│ ├── workflow-setup.png
│ ├── github-template.png
│ ├── criando-templates.png
│ ├── reusing-workflows.png
│ ├── github-actions-samples.png
│ ├── calling-reusable-workflow.png
│ ├── reusing-workflows-template.png
│ └── showing-reusable-workflow.png
├── autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7
├── Untitled.png
├── Untitled1.png
├── Untitled2.png
├── Untitled3.png
├── Untitled4.png
├── Untitled5.png
├── Untitled6.png
├── Untitled7.png
├── Screenshot_2023-05-19_at_10.57.04.png
└── Screenshot_2023-05-19_at_11.00.23.png
├── e-viavel-programar-em-csharp-no-linux-em-2022
├── images
│ ├── imagem-rider.png
│ ├── imagem-vscode.png
│ └── iImagem-extensoes.png
└── index.md
├── arrays-monodimensionais-e-multidimensionais-no-csharp
└── images
│ ├── matriz.png
│ └── vetor.png
├── github-trabalhando-com-projetos-equipes-e-organizacoes
└── images
│ ├── people.png
│ ├── new-team.png
│ ├── new-team-view.png
│ ├── organization.png
│ ├── new-organization.png
│ ├── profile-projetcs.png
│ ├── new-organization-form.png
│ ├── organization-projects.png
│ ├── profile-organizations.png
│ └── repository-projects.png
├── uma-visao-geral-do-blazor
└── images
│ ├── Screenshot_2023-10-12_at_12.15.29.png
│ ├── Screenshot_2023-10-12_at_12.15.55.png
│ ├── Screenshot_2023-10-12_at_12.17.20.png
│ ├── Screenshot_2023-10-12_at_12.18.18.png
│ ├── Screenshot_2023-10-13_at_08.25.47.png
│ ├── Screenshot_2023-10-13_at_08.26.05.png
│ ├── Screenshot_2023-10-13_at_08.57.59.png
│ ├── Screenshot_2023-10-13_at_08.59.18.png
│ └── Screenshot_2023-10-13_at_08.59.31.png
├── adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha
└── images
│ ├── 10-review.png
│ ├── 01-workflow.png
│ ├── 02-settings.png
│ ├── 03-environment.png
│ ├── 06-add-required.png
│ ├── 12-prd-approved.png
│ ├── 04-new-environment.png
│ ├── 05-add-environment.png
│ ├── 07-save-required.png
│ ├── 09-waiting-review.png
│ ├── 13-repository-env.png
│ ├── 09-waiting-review 1.png
│ ├── 08-adding-environment.png
│ └── 11-review-and-approve.png
├── dotnet-cli-introducao-e-principais-comandos
└── Images
│ └── image-terminal-cli.png
├── comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta
└── images
│ ├── run.png
│ ├── new-query.png
│ ├── select-grupo.png
│ ├── new-connection.png
│ ├── select-usuario.png
│ ├── connecting-master.png
│ ├── database-with-fks.png
│ ├── run-confirmation.png
│ ├── select-categoria.png
│ └── database-without-fks.png
├── obsessao-por-tipos-primitivos
└── images
│ ├── ESQUEMATIZACAO-OBSESSAO-POR-TIPOS-PRIMITIVOS.png
│ └── ESQUEMATIZACAO-OBSESSAO-POR-TIPOS-PRIMITIVOS-DARKMODE.png
├── trabalhando-com-mais-de-uma-configuracao-do-git-em-um-unico-computador
└── images
│ ├── share.png
│ └── banner.jpg
├── publicando-aplicativo-web-no-azure-utilizando-identity-sqLite-e-github-actions
└── images
│ ├── newrepo.png
│ ├── applicationuser.png
│ └── registerconfirmation.png
├── executando-processamentos-em-segundo-plano-no-dotnet-com-o-hangfire
└── imagens
│ ├── console-log-jobs-1.jpeg
│ └── dashboard-hangfire-1.jpeg
├── comecando-com-sql-server-na-pratica-consulta-avancada-edicao-e-remocao-de-dados
└── images
│ ├── path-views.png
│ └── select-evento.png
├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular
└── images
│ ├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular_icon.jpg
│ ├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular_share.jpg
│ ├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular_banner.jpg
│ ├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular-estrutura.png
│ ├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-exemplo-login.gif
│ ├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-route-modules.jpg
│ ├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-route-outlet.jpg
│ ├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular-importando-modulos.jpg
│ ├── login-logout-protecao-de-rotas-envio-de-tokens-com-angular-nossos-componentes.jpg
│ └── login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-exemplo-login-teste.jpg
├── masterclass-flutter-mobx-mvc-mvvm
└── index.md
├── .github
└── ISSUE_TEMPLATE
│ └── submiss-o-de-artigo.md
├── pwa-hibrido-nativo
└── index.md
├── criando-seu-primeiro-identity-server
└── index.md
├── lendo-arquivos-em-csharp
└── index.md
├── dotnet-7-ainda-mais-rapido
└── index.md
├── csharp-tipos-anonimos
└── index.md
├── csharp-as-is
└── index.md
├── dotnet-platform-specific
└── index.md
├── csharp-action
└── index.md
├── windows-11-instalacao
└── index.md
├── csharp-11-o-que-vem-por-ai
└── index.md
├── data-driven-vs-domain-driven
└── index.md
├── exception-vs-domain-notification
└── index.md
├── mongodb-docker
└── index.md
├── aspnet-logger
└── index.md
├── aspnet-developer-roadmap
└── index.md
├── README.md
├── removendo-codigo-desnecessario-dotnet
└── index.md
├── aspnet-qrcode
└── index.md
├── csharp-parse-tryparse
└── index.md
├── fundamentos-testes-de-unidade
└── index.md
├── aspnet-serilog
└── index.md
├── dotnetconf-dotnetcore-resumo
└── index.md
├── flutter-por-onde-comecar
└── index.md
├── aspnet-minimal-signalr
└── index.md
├── novidades-aspnet-7
└── index.md
├── descomplicando-o-model-biding-no-aspnet-core
└── index.md
├── mudancas-ef-core-5
└── index.md
└── csharp-deconstruct
└── index.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/aspnet-refit2/images/swagger1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-refit2/images/swagger1.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/001.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/002.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/003.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/003.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/004.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/005.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/005.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/006.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/006.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/007.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/007.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/008.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/008.png
--------------------------------------------------------------------------------
/aspnet-refit2/images/swagger1post.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-refit2/images/swagger1post.png
--------------------------------------------------------------------------------
/aspnet-refit2/images/swagger3get.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-refit2/images/swagger3get.png
--------------------------------------------------------------------------------
/aspnet-refit2/images/swagger3post.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-refit2/images/swagger3post.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/banner.jpg
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/share.png
--------------------------------------------------------------------------------
/csharp-implicit-operators/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/csharp-implicit-operators/.DS_Store
--------------------------------------------------------------------------------
/csharp-paralelismo/images/saida1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/csharp-paralelismo/images/saida1.png
--------------------------------------------------------------------------------
/csharp-paralelismo/images/saida2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/csharp-paralelismo/images/saida2.png
--------------------------------------------------------------------------------
/inversion-of-control/images/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/inversion-of-control/images/share.png
--------------------------------------------------------------------------------
/aspnet-health-check/images/request1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-health-check/images/request1.png
--------------------------------------------------------------------------------
/aspnet-health-check/images/request2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-health-check/images/request2.png
--------------------------------------------------------------------------------
/aspnet-health-check/images/request3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-health-check/images/request3.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled.png
--------------------------------------------------------------------------------
/inversion-of-control/images/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/inversion-of-control/images/banner.jpg
--------------------------------------------------------------------------------
/aspnet-health-check/images/baltaLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-health-check/images/baltaLogo.png
--------------------------------------------------------------------------------
/aspnet-health-check/images/baltaLogo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-health-check/images/baltaLogo2.png
--------------------------------------------------------------------------------
/aspnet-health-check/images/dashboard1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-health-check/images/dashboard1.png
--------------------------------------------------------------------------------
/aspnet-health-check/images/dashboard2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-health-check/images/dashboard2.png
--------------------------------------------------------------------------------
/aspnet-health-check/images/dashboard3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-health-check/images/dashboard3.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_1.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_10.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_11.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_12.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_13.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_14.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_2.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_3.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_4.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_5.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_6.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_7.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_8.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Untitled_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Untitled_9.png
--------------------------------------------------------------------------------
/blazor-rotas-navegacao/images/Untitled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-rotas-navegacao/images/Untitled.png
--------------------------------------------------------------------------------
/aspnet-async-streaming/images/asyncenum.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/aspnet-async-streaming/images/asyncenum.gif
--------------------------------------------------------------------------------
/blazor-rotas-navegacao/images/Untitled 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-rotas-navegacao/images/Untitled 1.png
--------------------------------------------------------------------------------
/blazor-rotas-navegacao/images/Untitled 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-rotas-navegacao/images/Untitled 2.png
--------------------------------------------------------------------------------
/blazor-rotas-navegacao/images/Untitled 3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-rotas-navegacao/images/Untitled 3.png
--------------------------------------------------------------------------------
/dependency-inversion-principle/images/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/dependency-inversion-principle/images/share.png
--------------------------------------------------------------------------------
/minimal-apis-especificar-porta/images/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/minimal-apis-especificar-porta/images/share.png
--------------------------------------------------------------------------------
/o-futuro-do-aspnet-e-blazor/images/Untitled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-futuro-do-aspnet-e-blazor/images/Untitled.png
--------------------------------------------------------------------------------
/o-que-e-autenticacao-e-autorizacao/Untitled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-que-e-autenticacao-e-autorizacao/Untitled.png
--------------------------------------------------------------------------------
/dependency-inversion-principle/images/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/dependency-inversion-principle/images/banner.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/image-example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/image-example.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/table-example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/table-example.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/wiki-repo-item.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/wiki-repo-item.jpg
--------------------------------------------------------------------------------
/gestao-de-equipes-com-github/images/team-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-equipes-com-github/images/team-page.jpg
--------------------------------------------------------------------------------
/git-por-dentro-do-encanamento/images/image-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/git-por-dentro-do-encanamento/images/image-1.png
--------------------------------------------------------------------------------
/git-por-dentro-do-encanamento/images/image-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/git-por-dentro-do-encanamento/images/image-2.png
--------------------------------------------------------------------------------
/git-por-dentro-do-encanamento/images/image-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/git-por-dentro-do-encanamento/images/image-3.png
--------------------------------------------------------------------------------
/git-por-dentro-do-encanamento/images/image-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/git-por-dentro-do-encanamento/images/image-4.png
--------------------------------------------------------------------------------
/minimal-apis-especificar-porta/images/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/minimal-apis-especificar-porta/images/banner.jpg
--------------------------------------------------------------------------------
/o-futuro-do-aspnet-e-blazor/images/Untitled_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-futuro-do-aspnet-e-blazor/images/Untitled_1.png
--------------------------------------------------------------------------------
/o-futuro-do-aspnet-e-blazor/images/Untitled_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-futuro-do-aspnet-e-blazor/images/Untitled_2.png
--------------------------------------------------------------------------------
/o-futuro-do-aspnet-e-blazor/images/Untitled_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-futuro-do-aspnet-e-blazor/images/Untitled_3.png
--------------------------------------------------------------------------------
/o-futuro-do-aspnet-e-blazor/images/spa_drawio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-futuro-do-aspnet-e-blazor/images/spa_drawio.png
--------------------------------------------------------------------------------
/o-que-e-jwt/Screenshot_2023-05-16_at_12.41.01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-que-e-jwt/Screenshot_2023-05-16_at_12.41.01.png
--------------------------------------------------------------------------------
/o-que-e-jwt/Screenshot_2023-05-16_at_12.53.34.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-que-e-jwt/Screenshot_2023-05-16_at_12.53.34.png
--------------------------------------------------------------------------------
/o-que-e-jwt/Screenshot_2023-05-16_at_12.56.00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-que-e-jwt/Screenshot_2023-05-16_at_12.56.00.png
--------------------------------------------------------------------------------
/addtransient-addscoped-addsingleton/images/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/addtransient-addscoped-addsingleton/images/share.png
--------------------------------------------------------------------------------
/como-tirar-duvidas/images/start-new-discussion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-tirar-duvidas/images/start-new-discussion.png
--------------------------------------------------------------------------------
/documentacao-com-github/images/accordion-example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/accordion-example.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/clean-wiki-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/clean-wiki-page.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/discussion-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/discussion-page.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/first-structure.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/first-structure.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/second-structure.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/second-structure.jpg
--------------------------------------------------------------------------------
/testes-de-mutacao-stryke-dotnet/Images/img-final.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/testes-de-mutacao-stryke-dotnet/Images/img-final.png
--------------------------------------------------------------------------------
/testes-de-mutacao-stryke-dotnet/Images/img-url.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/testes-de-mutacao-stryke-dotnet/Images/img-url.png
--------------------------------------------------------------------------------
/addtransient-addscoped-addsingleton/images/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/addtransient-addscoped-addsingleton/images/banner.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/bad-readme-example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/bad-readme-example.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/wiki-example-result.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/wiki-example-result.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/wiki-final-summary.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/wiki-final-summary.jpg
--------------------------------------------------------------------------------
/hospedagem-gratuita-com-github/images/deploy-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/hospedagem-gratuita-com-github/images/deploy-page.jpg
--------------------------------------------------------------------------------
/hospedagem-gratuita-com-github/images/pages-option.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/hospedagem-gratuita-com-github/images/pages-option.jpg
--------------------------------------------------------------------------------
/hospedagem-gratuita-com-github/images/result-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/hospedagem-gratuita-com-github/images/result-page.jpg
--------------------------------------------------------------------------------
/testes-de-mutacao-stryke-dotnet/Images/img-killed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/testes-de-mutacao-stryke-dotnet/Images/img-killed.png
--------------------------------------------------------------------------------
/testes-de-mutacao-stryke-dotnet/Images/img-testes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/testes-de-mutacao-stryke-dotnet/Images/img-testes.png
--------------------------------------------------------------------------------
/gestao-de-equipes-com-github/images/create-team-form.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-equipes-com-github/images/create-team-form.jpg
--------------------------------------------------------------------------------
/gestao-de-equipes-com-github/images/team-members-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-equipes-com-github/images/team-members-page.jpg
--------------------------------------------------------------------------------
/gestao-de-organizacoes-com-github/images/people-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-organizacoes-com-github/images/people-page.jpg
--------------------------------------------------------------------------------
/gestao-de-organizacoes-com-github/images/person-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-organizacoes-com-github/images/person-page.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/manual-activity.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/manual-activity.jpg
--------------------------------------------------------------------------------
/hospedagem-gratuita-com-github/images/pages-settings.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/hospedagem-gratuita-com-github/images/pages-settings.jpg
--------------------------------------------------------------------------------
/testes-de-mutacao-stryke-dotnet/Images/img-mutantes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/testes-de-mutacao-stryke-dotnet/Images/img-mutantes.png
--------------------------------------------------------------------------------
/testes-de-mutacao-stryke-dotnet/Images/img-survived.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/testes-de-mutacao-stryke-dotnet/Images/img-survived.png
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/.vs/VSWorkspaceState.json:
--------------------------------------------------------------------------------
1 | {
2 | "ExpandedNodes": [
3 | ""
4 | ],
5 | "PreviewInSolutionExplorer": false
6 | }
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/.vs/slnx.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/utilizando-discord-repositorio-log-dotnet/.vs/slnx.sqlite
--------------------------------------------------------------------------------
/como-testar-o-dotnet-8-e-csharp-12-hoje-mesmo/images/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/como-testar-o-dotnet-8-e-csharp-12-hoje-mesmo/images/01.png
--------------------------------------------------------------------------------
/gestao-de-equipes-com-github/images/create-team-button.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-equipes-com-github/images/create-team-button.jpg
--------------------------------------------------------------------------------
/razor-pages-asp-net-core-qrcode/images/render-qrcode-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/razor-pages-asp-net-core-qrcode/images/render-qrcode-1.png
--------------------------------------------------------------------------------
/razor-pages-asp-net-core-qrcode/images/render-qrcode-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/razor-pages-asp-net-core-qrcode/images/render-qrcode-2.png
--------------------------------------------------------------------------------
/razor-pages-asp-net-core-qrcode/images/render-qrcode-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/razor-pages-asp-net-core-qrcode/images/render-qrcode-3.png
--------------------------------------------------------------------------------
/sqlserver-conhecendo-os-cursores/images/end-table-state.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/sqlserver-conhecendo-os-cursores/images/end-table-state.jpg
--------------------------------------------------------------------------------
/testes-de-mutacao-stryke-dotnet/Images/img-stryker-cli.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/testes-de-mutacao-stryke-dotnet/Images/img-stryker-cli.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 1.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 2.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 3.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 4.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 5.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 6.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 7.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled 8.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/Untitled.png
--------------------------------------------------------------------------------
/documentacao-com-github/images/discussion-feature-option.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/discussion-feature-option.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/add-new-item-option.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/add-new-item-option.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/change-issue-status.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/change-issue-status.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/edit-values-of-status.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/edit-values-of-status.jpg
--------------------------------------------------------------------------------
/migrations-efcore-dotnet-postgresql/images/marianarizzo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/migrations-efcore-dotnet-postgresql/images/marianarizzo.jpeg
--------------------------------------------------------------------------------
/o-futuro-do-aspnet-e-blazor/images/Untitled_Diagram_drawio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/o-futuro-do-aspnet-e-blazor/images/Untitled_Diagram_drawio.png
--------------------------------------------------------------------------------
/sqlserver-conhecendo-os-cursores/images/first-table-state.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/sqlserver-conhecendo-os-cursores/images/first-table-state.jpg
--------------------------------------------------------------------------------
/blazor-render-modes/images/Screenshot_2023-10-18_at_08.28.33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Screenshot_2023-10-18_at_08.28.33.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Screenshot_2023-10-18_at_08.34.42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Screenshot_2023-10-18_at_08.34.42.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Screenshot_2023-10-18_at_08.40.28.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Screenshot_2023-10-18_at_08.40.28.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Screenshot_2023-10-18_at_08.40.38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Screenshot_2023-10-18_at_08.40.38.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Screenshot_2023-10-18_at_08.41.00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Screenshot_2023-10-18_at_08.41.00.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Screenshot_2023-10-18_at_08.59.03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Screenshot_2023-10-18_at_08.59.03.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Screenshot_2023-10-18_at_09.17.01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Screenshot_2023-10-18_at_09.17.01.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Screenshot_2023-10-18_at_09.17.17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Screenshot_2023-10-18_at_09.17.17.png
--------------------------------------------------------------------------------
/blazor-render-modes/images/Screenshot_2023-10-18_at_09.17.31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/blazor-render-modes/images/Screenshot_2023-10-18_at_09.17.31.png
--------------------------------------------------------------------------------
/criando-projetos-dotnet-via-console/images/dotnet-sdks-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-projetos-dotnet-via-console/images/dotnet-sdks-list.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/ci-cd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/ci-cd.png
--------------------------------------------------------------------------------
/documentacao-com-github/images/added-statistics-to-structure.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/added-statistics-to-structure.jpg
--------------------------------------------------------------------------------
/gestao-de-equipes-com-github/images/creating-by-organization.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-equipes-com-github/images/creating-by-organization.jpg
--------------------------------------------------------------------------------
/gestao-de-equipes-com-github/images/link-repository-to-team.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-equipes-com-github/images/link-repository-to-team.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/link-issue-with-project.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/link-issue-with-project.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/selecting-project-style.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/selecting-project-style.jpg
--------------------------------------------------------------------------------
/hospedagem-gratuita-com-github/images/organization-settings.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/hospedagem-gratuita-com-github/images/organization-settings.jpg
--------------------------------------------------------------------------------
/documentacao-com-github/images/way-to-discussion-feature-option.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/documentacao-com-github/images/way-to-discussion-feature-option.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/creating-project-team-menu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/creating-project-team-menu.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/creating-project-user-menu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/creating-project-user-menu.jpg
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/images/img-swagger-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/utilizando-discord-repositorio-log-dotnet/images/img-swagger-1.png
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/images/img-swagger-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/utilizando-discord-repositorio-log-dotnet/images/img-swagger-2.png
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/images/img-swagger-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/utilizando-discord-repositorio-log-dotnet/images/img-swagger-3.png
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled.png
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled1.png
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled2.png
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled3.png
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled4.png
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled5.png
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled6.png
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Untitled7.png
--------------------------------------------------------------------------------
/e-viavel-programar-em-csharp-no-linux-em-2022/images/imagem-rider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/e-viavel-programar-em-csharp-no-linux-em-2022/images/imagem-rider.png
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/save-changes-on-project-view.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/save-changes-on-project-view.jpg
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/.vs/utilizando-discord-repositorio-log-dotnet/project-colors.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": 1,
3 | "ProjectMap": {},
4 | "NextColorIndex": 0
5 | }
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/images/img-info-discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/utilizando-discord-repositorio-log-dotnet/images/img-info-discord.png
--------------------------------------------------------------------------------
/arrays-monodimensionais-e-multidimensionais-no-csharp/images/matriz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/arrays-monodimensionais-e-multidimensionais-no-csharp/images/matriz.png
--------------------------------------------------------------------------------
/arrays-monodimensionais-e-multidimensionais-no-csharp/images/vetor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/arrays-monodimensionais-e-multidimensionais-no-csharp/images/vetor.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/repositories.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/repositories.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/workflow-setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/workflow-setup.png
--------------------------------------------------------------------------------
/e-viavel-programar-em-csharp-no-linux-em-2022/images/imagem-vscode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/e-viavel-programar-em-csharp-no-linux-em-2022/images/imagem-vscode.png
--------------------------------------------------------------------------------
/gestao-de-organizacoes-com-github/images/organization-menu-settings.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-organizacoes-com-github/images/organization-menu-settings.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/creating-an-issue-on-repository.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/creating-an-issue-on-repository.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/result-of-new-repository-column.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/result-of-new-repository-column.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/unsaved-changes-on-project-view.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/unsaved-changes-on-project-view.jpg
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/people.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/people.png
--------------------------------------------------------------------------------
/uma-visao-geral-do-blazor/images/Screenshot_2023-10-12_at_12.15.29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/uma-visao-geral-do-blazor/images/Screenshot_2023-10-12_at_12.15.29.png
--------------------------------------------------------------------------------
/uma-visao-geral-do-blazor/images/Screenshot_2023-10-12_at_12.15.55.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/uma-visao-geral-do-blazor/images/Screenshot_2023-10-12_at_12.15.55.png
--------------------------------------------------------------------------------
/uma-visao-geral-do-blazor/images/Screenshot_2023-10-12_at_12.17.20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/uma-visao-geral-do-blazor/images/Screenshot_2023-10-12_at_12.17.20.png
--------------------------------------------------------------------------------
/uma-visao-geral-do-blazor/images/Screenshot_2023-10-12_at_12.18.18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/uma-visao-geral-do-blazor/images/Screenshot_2023-10-12_at_12.18.18.png
--------------------------------------------------------------------------------
/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.25.47.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.25.47.png
--------------------------------------------------------------------------------
/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.26.05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.26.05.png
--------------------------------------------------------------------------------
/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.57.59.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.57.59.png
--------------------------------------------------------------------------------
/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.59.18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.59.18.png
--------------------------------------------------------------------------------
/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.59.31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/uma-visao-geral-do-blazor/images/Screenshot_2023-10-13_at_08.59.31.png
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/images/img-criando-webhook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/utilizando-discord-repositorio-log-dotnet/images/img-criando-webhook.png
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/images/img-info-discord-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/utilizando-discord-repositorio-log-dotnet/images/img-info-discord-2.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/10-review.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/10-review.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/github-template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/github-template.png
--------------------------------------------------------------------------------
/dotnet-cli-introducao-e-principais-comandos/Images/image-terminal-cli.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/dotnet-cli-introducao-e-principais-comandos/Images/image-terminal-cli.png
--------------------------------------------------------------------------------
/e-viavel-programar-em-csharp-no-linux-em-2022/images/iImagem-extensoes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/e-viavel-programar-em-csharp-no-linux-em-2022/images/iImagem-extensoes.png
--------------------------------------------------------------------------------
/gestao-de-organizacoes-com-github/images/organization-menu-moderation.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-organizacoes-com-github/images/organization-menu-moderation.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/add-repository-column-to-project.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/add-repository-column-to-project.jpg
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/creating-project-repository-menu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/creating-project-repository-menu.jpg
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/new-team.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/new-team.png
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/images/img-solution-projeto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/utilizando-discord-repositorio-log-dotnet/images/img-solution-projeto.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/01-workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/01-workflow.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/02-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/02-settings.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/criando-templates.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/criando-templates.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/reusing-workflows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/reusing-workflows.png
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/creating-project-organization-menu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/creating-project-organization-menu.jpg
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/03-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/03-environment.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/06-add-required.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/06-add-required.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/12-prd-approved.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/12-prd-approved.png
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/new-team-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/new-team-view.png
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/organization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/organization.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/04-new-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/04-new-environment.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/05-add-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/05-add-environment.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/07-save-required.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/07-save-required.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/09-waiting-review.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/09-waiting-review.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/13-repository-env.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/13-repository-env.png
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/run.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/github-actions-samples.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/github-actions-samples.png
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/new-organization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/new-organization.png
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/profile-projetcs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/profile-projetcs.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/09-waiting-review 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/09-waiting-review 1.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/calling-reusable-workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/calling-reusable-workflow.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/reusing-workflows-template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/reusing-workflows-template.png
--------------------------------------------------------------------------------
/criando-workflows-reutilizaveis-github-actions/images/showing-reusable-workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-workflows-reutilizaveis-github-actions/images/showing-reusable-workflow.png
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/saving-changes-of-edition-values-of-status.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/saving-changes-of-edition-values-of-status.jpg
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/08-adding-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/08-adding-environment.png
--------------------------------------------------------------------------------
/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/11-review-and-approve.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/adicionando-etapa-de-aprovacao-fluxo-de-trabalho-gha/images/11-review-and-approve.png
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/new-query.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/new-query.png
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/new-organization-form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/new-organization-form.png
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/organization-projects.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/organization-projects.png
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/profile-organizations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/profile-organizations.png
--------------------------------------------------------------------------------
/github-trabalhando-com-projetos-equipes-e-organizacoes/images/repository-projects.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/github-trabalhando-com-projetos-equipes-e-organizacoes/images/repository-projects.png
--------------------------------------------------------------------------------
/obsessao-por-tipos-primitivos/images/ESQUEMATIZACAO-OBSESSAO-POR-TIPOS-PRIMITIVOS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/obsessao-por-tipos-primitivos/images/ESQUEMATIZACAO-OBSESSAO-POR-TIPOS-PRIMITIVOS.png
--------------------------------------------------------------------------------
/trabalhando-com-mais-de-uma-configuracao-do-git-em-um-unico-computador/images/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/trabalhando-com-mais-de-uma-configuracao-do-git-em-um-unico-computador/images/share.png
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/select-grupo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/select-grupo.png
--------------------------------------------------------------------------------
/trabalhando-com-mais-de-uma-configuracao-do-git-em-um-unico-computador/images/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/trabalhando-com-mais-de-uma-configuracao-do-git-em-um-unico-computador/images/banner.jpg
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/new-connection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/new-connection.png
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/select-usuario.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/select-usuario.png
--------------------------------------------------------------------------------
/gestao-de-projetos-com-github/images/result-of-save-changes-of-edition-of-status-values.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/gestao-de-projetos-com-github/images/result-of-save-changes-of-edition-of-status-values.jpg
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Screenshot_2023-05-19_at_10.57.04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Screenshot_2023-05-19_at_10.57.04.png
--------------------------------------------------------------------------------
/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Screenshot_2023-05-19_at_11.00.23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/autenticacao-e-autorizacao-com-jwt-e-bearer-no-aspnet-7/Screenshot_2023-05-19_at_11.00.23.png
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/connecting-master.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/connecting-master.png
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/database-with-fks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/database-with-fks.png
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/run-confirmation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/run-confirmation.png
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/select-categoria.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/select-categoria.png
--------------------------------------------------------------------------------
/obsessao-por-tipos-primitivos/images/ESQUEMATIZACAO-OBSESSAO-POR-TIPOS-PRIMITIVOS-DARKMODE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/obsessao-por-tipos-primitivos/images/ESQUEMATIZACAO-OBSESSAO-POR-TIPOS-PRIMITIVOS-DARKMODE.png
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/database-without-fks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-estrutura-insercao-e-consulta/images/database-without-fks.png
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/criando-api-zero-dotnet-core-3-1-ef-core_icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/criando-api-zero-dotnet-core-3-1-ef-core_icon.jpg
--------------------------------------------------------------------------------
/publicando-aplicativo-web-no-azure-utilizando-identity-sqLite-e-github-actions/images/newrepo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/publicando-aplicativo-web-no-azure-utilizando-identity-sqLite-e-github-actions/images/newrepo.png
--------------------------------------------------------------------------------
/utilizando-discord-repositorio-log-dotnet/.vs/utilizando-discord-repositorio-log-dotnet/v17/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/utilizando-discord-repositorio-log-dotnet/.vs/utilizando-discord-repositorio-log-dotnet/v17/.suo
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/criando-api-zero-dotnet-core-3-1-ef-core_banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/criando-api-zero-dotnet-core-3-1-ef-core_banner.jpg
--------------------------------------------------------------------------------
/criando-api-zero-dotnet-core-3-1-ef-core/images/criando-api-zero-dotnet-core-3-1-ef-core_share.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/criando-api-zero-dotnet-core-3-1-ef-core/images/criando-api-zero-dotnet-core-3-1-ef-core_share.jpg
--------------------------------------------------------------------------------
/executando-processamentos-em-segundo-plano-no-dotnet-com-o-hangfire/imagens/console-log-jobs-1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/executando-processamentos-em-segundo-plano-no-dotnet-com-o-hangfire/imagens/console-log-jobs-1.jpeg
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-consulta-avancada-edicao-e-remocao-de-dados/images/path-views.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-consulta-avancada-edicao-e-remocao-de-dados/images/path-views.png
--------------------------------------------------------------------------------
/executando-processamentos-em-segundo-plano-no-dotnet-com-o-hangfire/imagens/dashboard-hangfire-1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/executando-processamentos-em-segundo-plano-no-dotnet-com-o-hangfire/imagens/dashboard-hangfire-1.jpeg
--------------------------------------------------------------------------------
/comecando-com-sql-server-na-pratica-consulta-avancada-edicao-e-remocao-de-dados/images/select-evento.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/comecando-com-sql-server-na-pratica-consulta-avancada-edicao-e-remocao-de-dados/images/select-evento.png
--------------------------------------------------------------------------------
/publicando-aplicativo-web-no-azure-utilizando-identity-sqLite-e-github-actions/images/applicationuser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/publicando-aplicativo-web-no-azure-utilizando-identity-sqLite-e-github-actions/images/applicationuser.png
--------------------------------------------------------------------------------
/publicando-aplicativo-web-no-azure-utilizando-identity-sqLite-e-github-actions/images/registerconfirmation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/publicando-aplicativo-web-no-azure-utilizando-identity-sqLite-e-github-actions/images/registerconfirmation.png
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular_icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular_icon.jpg
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular_share.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular_share.jpg
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular_banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular_banner.jpg
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-estrutura.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-estrutura.png
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-exemplo-login.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-exemplo-login.gif
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-route-modules.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-route-modules.jpg
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-route-outlet.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-route-outlet.jpg
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-importando-modulos.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-importando-modulos.jpg
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-nossos-componentes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-nossos-componentes.jpg
--------------------------------------------------------------------------------
/masterclass-flutter-mobx-mvc-mvvm/index.md:
--------------------------------------------------------------------------------
1 | Este artigo foi movido para um vídeo. [Clique aqui para visualizar](https://www.youtube.com/watch?v=fsrJ_tNrOFk).
2 |
3 | Código Fonte
4 | ------------
5 |
6 | [https://github.com/andrebaltieri/flutter-mobx-mvc-mvvm-masterclass](https://github.com/andrebaltieri/flutter-mobx-mvc-mvvm-masterclass)
--------------------------------------------------------------------------------
/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-exemplo-login-teste.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/balta-io/blog/HEAD/login-logout-protecao-de-rotas-envio-de-tokens-com-angular/images/login-logout-protecao-de-rotas-envio-de-tokens-com-angular-app-exemplo-login-teste.jpg
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/submiss-o-de-artigo.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Submissão de artigo
3 | about: Preencha todas as informações corretamente para que possamos dar andamento
4 | ao seu artigo da forma mais rápida possível
5 | title: 'Proposta de artigo: TITULO DO ARTIGO AQUI'
6 | labels: proposta
7 | assignees: BrewertonSantos
8 |
9 | ---
10 |
11 | #### Qual título do artigo?
12 | =>
13 |
14 | #### Sobre o que você pretende falar neste artigo?
15 | =>
16 |
17 | #### Qual previsão para submissão deste artigo?
18 | => dd/MM/yyyy
19 |
--------------------------------------------------------------------------------
/pwa-hibrido-nativo/index.md:
--------------------------------------------------------------------------------
1 | Nesta última Terça Feira, 05 de Novembro de 2019, tive o prazer de receber o ilustre [**Rodrigo Branas**](https://www.youtube.com/rodrigobranas) para batermos um papo sobre PWAs, Híbridos e Nativos.
2 |
3 | Este é um assunto muito discutido, afinal é uma tomada de decisão muito importante em qualquer produto, e neste bate-papo falamos muito (Muito mesmo, quase 1 hora e quarenta minutos) sobre nossas opiniões sobre o assunto.
4 |
5 | Se você não pode acompanhar ao vivo, abaixo estão as gravações em vídeo e MP3.
6 |
7 | Este conteúdo também está disponível no nosso [Podcast no Spotify](https://open.spotify.com/show/7w5X2POx4biBytGqm0q51p?si=CpTvmGE6RSu-AvYdHCtQcA) e [Canal no YouTube](https://www.youtube.com/watch?v=6aItb7Df8to).
--------------------------------------------------------------------------------
/criando-seu-primeiro-identity-server/index.md:
--------------------------------------------------------------------------------
1 | No artigo [anterior](https://balta.io/artigos/identity-server) demos uma olhada no **IdentityServer** e entendemos seu propósito e fundamentos.
2 |
3 | Neste artigo vamos dar nossos primeiros passos no Identity Server e criar nosso primeiro servidor de identidade.
4 |
5 | ## Índice
6 | * [Identity Server](https://balta.io/artigos/identity-server)
7 | * **Criando seu primeiro Identity Server**
8 |
9 | ## Templates
10 |
11 | Embora você possa criar uma aplicação vazia e depois adicionar os pacotes necessários para o Identity Server funcionar, é muito mais fácil utilizar um template já pronto.
12 |
13 | > **IMPORTANTE:** Normalmente mantemos o nosso servidor de identidade em um projeto separado, então não se preocupe tanto com a estrutura do projeto aqui.
14 |
15 | Para instalar os templates oficiais do Identity Server, você deve executar a seguinte linha de comando.
16 |
17 | ```
18 | dotnet new -i IdentityServer4.Templates
19 | ```
20 |
21 | ## Criando um Identity Server
22 |
23 | Existem vários templates disponíveis e vamos ver alguns aqui, começando pelo mais básico, que particularmente uso bastante.
24 |
25 | Desta forma, após instalar os templates, podemos executar a criação de um servidor de identidade utilizando o comando abaixo.
26 |
27 | ```
28 | dotnet new is4empty -n MeuIsServer
29 | ```
30 |
31 | Este processo vai criar um Web App que roda na porta 5001 e caso precise mudar esta opção, é só alterar o arquivo Properties\launchSettings.json.
32 |
33 | ## Executando o Identity Server
34 |
35 | Com a aplicação criada, podemos executá-la, pois nosso servidor já está rodando e pronto para ser configurado.
36 |
37 | ```
38 | cd MeuIsServer
39 | dotnet watch run
40 | ```
41 |
42 | Para verificar se o servidor está rodando adequadamente, basta acessar a URL https://localhost:5001/.well-known/openid-configuration.
43 |
44 | ## Conclusão
45 |
46 | Prontinho, em minutos você tem um servidor de identidade pronto para ser configurado e distribuído.
47 |
48 | Nos próximos artigos veremos como configurar e conectar nossos Apps e APIs neste servidor.
--------------------------------------------------------------------------------
/minimal-apis-especificar-porta/index.md:
--------------------------------------------------------------------------------
1 | Aprenda a especificar a porta e configurar os detalhes do seu servidor Web na hora de rodar aplicações ASP.NET.
2 |
3 | ## Minimal APIs - Especificar a porta
4 | Tanto o ASP.NET MVC quando as Minimal APIs permitem a configuração dos detalhes da execução da aplicação.
5 |
6 | Em determinados cenários, mais controlados principalmente, precisamos executar a aplicação em uma porta específica.
7 |
8 | Desta forma, podemos passar a **URL** de execução que desejamos no método `Run`.
9 |
10 | ```csharp
11 | var app = WebApplication.Create(args);
12 |
13 | app.MapGet("/", () => "Hello World!");
14 |
15 | app.Run("http://localhost:3000"); // Aqui
16 | ```
17 |
18 | ## Minimal APIs - Especificar várias portas
19 | Da mesma forma, podemos especificar várias portas, utilizando o método `Urls.Add(<>)`, como mostrado abaixo.
20 |
21 | Isto fará com que o servidor fique ouvindo em todas as portas especificadas.
22 |
23 | ```csharp
24 | var app = WebApplication.Create(args);
25 |
26 | app.Urls.Add("http://localhost:3000");
27 | app.Urls.Add("http://localhost:4000");
28 |
29 | app.MapGet("/", () => "Hello World");
30 |
31 | app.Run();
32 | ```
33 | [](https://balta.io/carreiras/desenvolvedor-backend-dotnet)
34 |
35 | ## Minimal APIs - Atribuir a porta dinamicamente
36 | Porém, caso queira especificar a porta durante a execução, ou seja, não deixar isto especificado no código, podemos especificar o parâmetro `--urls` durante a execução.
37 |
38 | ```
39 | dotnet run --urls="https://localhost:1234"
40 | ```
41 |
42 | ## Minimal APIs - Atribuir a porta via variável de ambiente
43 |
44 | Para finalizar, podemos utilizar as variáveis de ambiente, neste caso a **PORT** para definir a porta.
45 |
46 | Desta forma, podemos recuperar a variável de ambiente utilizando o `Environment.GetEnvironmentVariable(<>)`.
47 |
48 | ```csharp
49 | var app = WebApplication.Create(args);
50 |
51 | var port = Environment.GetEnvironmentVariable("PORT") ?? "3000";
52 |
53 | app.MapGet("/", () => "Hello World");
54 |
55 | app.Run($"http://localhost:{port}");
56 | ```
57 |
58 | ## Fontes
59 | * [Documentação Oficial do ASP.NET](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0)
60 |
--------------------------------------------------------------------------------
/lendo-arquivos-em-csharp/index.md:
--------------------------------------------------------------------------------
1 | Neste artigo vamos aprender algumas formas que temos para ler arquivos em C# com o menor esforço possível.
2 |
3 | ## Lendo arquivos em C#
4 | Ler arquivos em C# não é uma tarefa difícil e a forma mais simples e direta de fazer isto é utilizando o método `ReadAllText` da classe estática `File`.
5 |
6 | No exemplo abaixo temos um programa completo que faz a leitura de um arquivo e exibe seu conteúdo na tela utilizando o `Console.WriteLine`.
7 |
8 |
9 | ```csharp
10 | // Lê um arquivo inteiro
11 | var data = File.ReadAllText("C:\\text-file.txt");
12 | Console.WriteLine(data);
13 | ```
14 |
15 | ## Lendo arquivos em C# linha a linha
16 | Como notamos no método anterior, não iteramos sobre o arquivo, apenas pegamos seu conteúdo e exibimos na tela.
17 |
18 | Para iterar pelas linhas do arquivo, temos um método chamado `ReadAllLines` que retorna um **Array** de `string`, que pode ser iterado futuramente.
19 |
20 | No exemplo abaixo temos um programa completo que faz a leitura de um arquivo e exibe seu conteúdo na tela utilizando o `Console.WriteLine`.
21 |
22 | ```csharp
23 | // Lê um arquivo linha a linha
24 | var lines = File.ReadAllLines("C:\\text-file.txt");
25 | foreach (var line in lines)
26 | Console.WriteLine(line);
27 | ```
28 |
29 | ## StreamReader
30 | Uma outra forma muito solicitada é a leitura de arquivos linha a linha. Na verdade se um arquivo é muito grande, ler ele por completo pode acarretar em estouro de memória.
31 |
32 | Para isto, uma ótima solução é utilizar o `StreamReader` em conjunto ao `using` que fará a leitura do arquivo em blocos (Streaming).
33 |
34 | Toda vez que fazemos um **Stream**, ocorre a possibilidade do arquivo ficar aberto por mais tempo que o necessário em memória, por isto é quase que obrigatório o uso do `Dispose` que neste caso já é feito pelo `using`.
35 |
36 | No exemplo abaixo temos um programa completo que faz a leitura de um arquivo e exibe seu conteúdo na tela utilizando o `Console.WriteLine`.
37 |
38 | ```csharp
39 | using var file = new StreamReader("C:\\text-file.txt");
40 | string? line;
41 |
42 | while ((line = file.ReadLine()) != null)
43 | Console.WriteLine(line);
44 |
45 | file.Close();
46 | ```
47 |
48 | ## Conclusão
49 | C# não é difícil, muitas vezes nós complicamos muito as coisas que podem (E devem) ser simples! Ler arquivos é uma tarefa comum em todas as linguagens e o C# torna isto simples e direto ao ponto!
50 |
--------------------------------------------------------------------------------
/dotnet-7-ainda-mais-rapido/index.md:
--------------------------------------------------------------------------------
1 | Existe um motivo pelo qual o .NET 7 vai ser muito mais rápido do que o .NET 6, e você não precisar alterar nenhuma linha de código para se beneficiar disto.
2 |
3 | ## Vídeo
4 | [](https://www.youtube.com/watch?v=Vae07KDcpaw)
5 |
6 | ## Transcrição
7 | Estamos falando do AOT ou **Ahead of time**, um tipo de compilação que deixa tudo muito mais otimizado, mas é claro que isto tem um preço.
8 |
9 | O .NET é um dos Frameworks mais rápidos do mercado, chegando a ser até 10x mais rápido que o Node e só perdendo (Por pouca diferença) para o Rust.
10 |
11 | Atualmente o .NET que conhecemos, na versão 6, trabalha com um tipo de compilação chamado JIT, ou Just In Time, algo como “sob demanda”.
12 | O que acontece é que nossas aplicações não são completamente compiladas, alguns pedaços dela são compilados sob demanda, conforme a aplicação é utilizada.
13 |
14 | Este processo permite que o pacote final da aplicação fique menor, e que o tempo de compilação demore menos, o que para alguns casos pode impactar bastante.
15 |
16 | Porém, existe uma outra forma de entregar as aplicações, completamente compiladas, com o que chamamos de AOT ou Ahead of Time, algo como a frente do tempo.
17 |
18 | Neste modelo nós temos tudo exatamente compilado, extremamente otimizado, mas como resultado temos pacotes maiores e o tempo de compilação também demora.
19 |
20 | A grande questão é que hoje, no .NET 6 só é possível utilizar o JIT, mais especificamente o Ryu JIT que é o responsável por “pré-compilar” nossas aplicações.
21 |
22 | Mas isto vai mudar no .NET 7, com a inclusão de um compilador AOT nativo, o que permite fazer este tradeoff sem mudar uma ÚNICA LINHA de código.
23 |
24 | Então se você precisa da máxima performance e não está preocupado com tempo de Build do seu projeto, o AOT é uma mudança significativa para você.
25 |
26 | Claro que o JIT será mantido, da mesma forma como temos hoje, só será uma adição, um item a mais no leque de possibilidades.
27 |
28 | O mais interessante de tudo isto, é que esta novidade será aplicada ao .NET de uma forma geral, e poderá beneficiar diversos frameworks que utilizamos como ASP.NET, Blazor e MAUI.
29 |
30 | Particularmente, eu estou bem ansioso pelo .NET 7 que sai em Novembro deste ano. Já saiu a Preview 3 e você pode acompanhar todas as novidades aqui, então fica de olho no nosso conteúdo para não perder nada.
31 |
32 | ### Código Fonte
33 | * [GitHub - Steven Sanderson](https://github.com/SteveSandersonMS/BlazeOrbital)
--------------------------------------------------------------------------------
/como-tirar-duvidas/index.md:
--------------------------------------------------------------------------------
1 | Precisa de auxílio técnico durante os estudos? Entenda como tirar suas dúvidas online aqui no balta.io.
2 |
3 | ## Fórum
4 | Hoje (13/09) anunciamos a integração das discussões (Discussions) dos cursos em um novo Fórum, ainda dentro do GitHub.
5 |
6 | O novo Fórum vai permitir uma visão unificada das dúvidas, anúncios e enquetes para melhorar nosso conteúdo, coletar feedbacks e auxiliar melhor você.
7 |
8 | No modelo anterior, cada curso tinha seu fórum, muitas vezes duplicando perguntas ou mesmo tornando confuso o processo de tirar dúvidas.
9 |
10 | ## Como posso tirar uma dúvida?
11 | O primeiro passo é acessar o [Fórum por este link](https://github.com/balta-io/forum) e clicar em **Discussions**.
12 |
13 | 
14 |
15 | No menu lateral, temos as opções **Anúncios** para notícias (Privado, exclusivo para Administradores), **Enquetes** (Privado, exclusivo para Administradores) e **Tira Dúvidas** que é a opção que você deseja.
16 |
17 | 
18 |
19 | Selecione a opção **Tira Dúvidas** e pronto! Agora é só clicar em **New Discussion** e detalhar seu problema.
20 | 
21 |
22 | ## Como criar uma nova discussão (Dúvida)?
23 | Se você nunca utilizou o GitHub ou nunca criou uma **Discussion**, fique tranquilo que vamos mostrar um passo-a-passo aqui.
24 |
25 | Dentro da categoria **Tira Dúvidas**, clique em **New Discussion**.
26 |
27 | 
28 |
29 | Descreva sua dúvida colocando um título conciso e informando o **curso**, **módulo** e **aula** que está realizando.
30 | 
31 |
32 | Você pode anexar imagens do erro, isso vai nos ajudar a resolver seu problema mais rápido.
33 |
34 | É só clicar no rodapé da caixa de mensagem ou arrastar uma imagem para ela que o GitHub fará o upload.
35 | 
36 |
37 | Não se assuste, a imagem não vai aparecer no texto, apenas uma URL. O GitHub utiliza Markdown como formatação de texto, então fica tudo assim 👇
38 |
39 | 
40 |
41 | Você também pode adicionar trechos de código para nos ajudar a resolver seu problema, basta utilizar três crases (\`\`\`) seguido da linguagem que o código pertence, no exemplo abaixo utilizamos `csharp`.
42 |
43 | 
44 |
45 | Pronto, agora é só submeter a discussão que em breve retornaremos.
46 |
47 | ## Posso marcar o balta?
48 | Claro, você pode utilizar o @ para me marcar sempre que precisar.
49 |
50 | [Me segue lá também!](https://github.com/andrebaltieri)
51 |
52 | 
--------------------------------------------------------------------------------
/aspnet-async-streaming/index.md:
--------------------------------------------------------------------------------
1 | Neste artigo vamos conhecer o IAsyncEnumerable e como podemos fazer streaming de dados no ASP.NET 6.
2 |
3 | ## IAsyncEnumerable
4 | Desde o ASP.NET Core 3, podemos utilizar `IAsyncEnumerable` como retorno das **Actions** em nossos **Controllers**, porém sua efetividade não era tão completa.
5 |
6 | Ele basicamente aguardava a execução do método da mesma forma como aguardaria por um `IList`, pois não havia o conceito de `AsyncStreaming` ainda presente no ASP.NET.
7 |
8 | Na versão 6 do ASP.NET, este conceito foi introduzido e agora podemos "stremar" (Enviar por partes) dados para as interfaces. O melhor de tudo é que esta mudança ocorreu por baixo dos panos, nenhuma mudança de código é necessária.
9 |
10 | ### Yeld
11 | Você provavelmente já viu a palavra `yeld` em algum código C#, e sua tradução é render, produzir. Desta forma podemos retornar informações de um método sem necessariamente sair dele.
12 |
13 | ```csharp
14 | yield return 1000;
15 | ```
16 |
17 | ## Utilizando IAsyncEnumerable
18 | Sabendo que com o `yeld` podemos retornar uma informação sem necessariamente finalizar a execução do método, podemos usar o `IAsyncEnumerable` para criar uma lista assíncrona.
19 |
20 | Isto significa que não vamos aguardar toda a lista ser carregada, vamos receber os valores dela assim que os mesmos forem adicionados (Retornados com `yeld`).
21 |
22 | ```csharp
23 | private static async IAsyncEnumerable GetData()
24 | {
25 | for (var i = 1; i <= 1000; i++)
26 | {
27 | await Task.Delay(1000);
28 | yield return i;
29 | }
30 | }
31 | ```
32 |
33 | Para este exemplo, utilizamos um `IAsyncEnumerable`, seguido por um `for` que irá iterar por 1000 repetições.
34 |
35 | Como estamos utilizando `IAsyncEnumerable`, precisamos do `yeld return` e adicionamos um `Task.Delay(1000)` para demorar um segundo entre um retorno e outro.
36 |
37 | Para finalizar, não podemos esquecer de marcar o método como `async` já que estamos trabalhando com `IAsyncEnumerable` aqui.
38 |
39 | ## Streaming de dados
40 | Tendo um método que produz dados de forma assíncrona com `IAsyncEnumerable` já podemos fazer a mágica acontecer. Na verdade este mesmo código se rodado no ASP.NET 5 e ASP.NET 6 produz efeitos diferentes.
41 |
42 | No ASP.NET 5, este mesmo código aguardaria todos os dados serem retornados da lista (1000 segundos) para depois enviar tudo para tela, enquando no ASP.NET 6, isto é feito item a item.
43 |
44 | ```csharp
45 | [HttpGet("/")]
46 | public IAsyncEnumerable Get()
47 | {
48 | IAsyncEnumerable value = GetData();
49 | return value;
50 | }
51 | ```
52 |
53 | Note que temos apenas um retorno do tipo `IAsyncEnumerable`, em seguida recebemos os dados do método `GetData()` que criamos anteriormente e fazemos o envio para tela.
54 |
55 | Não há necessidade de configurar nenhuma informação adicional aqui, apenas retornar um `IAsyncEnumerable` já basta.
56 |
57 | 
58 |
59 | ## Conclusão
60 | Podemos utilizar o `IAsyncEnumerable` para enviar dados para tela ou outras interfaces no formato de **Stream** de forma simples e fácil no ASP.NET 6.
--------------------------------------------------------------------------------
/csharp-tipos-anonimos/index.md:
--------------------------------------------------------------------------------
1 | O C# é conhecido por sua tipagem, mas neste artigo vamos conhecer os vários tipos anônimos que temos nele.
2 |
3 | ## Tipar ou não tipar?
4 | O C# é uma linguagem muito dinâmica e versátil, o que significa que ela tem diversas aplicabilidades, como Web, Mobile, Desktop, IA e games.
5 |
6 | Dentre as várias coisas boas do C#, está sua tipagem forte, que implica na obrigatoriedade de um tipo para nossas variáveis.
7 |
8 | Abaixo temos um exemplo utilizando **JavaScript** e o mesmo utilizando **C#**, apenas para efeito de comparação.
9 |
10 | ```javascript
11 | let name = 'André Baltieri';
12 | ```
13 |
14 | ```csharp
15 | string name = "André Baltieri";
16 | ```
17 |
18 | [**Confira nosso artigo**](https://balta.io/blog/csharp) sobre C# para ficar por dentro de todas as funcionalidades dele.
19 |
20 | ### Quando não tipar?
21 | Um bom exemplo que passei, e não foi uma única vez, é o consumo de APIs externas. Em diversos momentos queremos fazer uma requisição a uma API, mas não queremos criar um tipo apenas para esperar seu retorno.
22 |
23 | Outro cenário que usei muito foi importação e exportação de dados, coisas pequenas, pontuais e que criar tipos ia tomar mais tempo.
24 |
25 | ## Dicionários
26 | Normalmente não comentamos sobre dicionários para criação de estruras, mas sim para listas. Porém, podemos utilizá-los para estruturar dados.
27 |
28 | ```csharp
29 | var person = new Dictionary
30 | {
31 | ["Name"] = "André Baltieri",
32 | ["BirthDate"] = DateTime.Now
33 | }
34 | ```
35 | Além do formato utilizando `[]`, podemos definir as estruturas utilizando `{}` com as chaves e valores como mostrado abaixo.
36 |
37 | ```csharp
38 | var person = new Dictionary
39 | {
40 | { "Name", "André Baltieri" },
41 | { "BirthDate", DateTime.Now }
42 | }
43 | ```
44 |
45 | ## Tipo anônimo
46 | Se você não quiser criar uma **classe**, **estrutura** ou **record** para seus dados, você pode utilizar um tipo anônimo no C#.
47 |
48 | ```csharp
49 | var person = new
50 | {
51 | Name = "André Baltieri",
52 | BirthDate = DateTime.Now
53 | }
54 | ```
55 | Como podemos notar, basta "fingir" que está instanciando uma classe e criar os nomes das propriedade e valores sob demanda.
56 |
57 | ## Tipagem com Records
58 | Caso queira uma abordagem com o mínimo de tipagem possível, a recomendação mais simples talvez sejam os `records`.
59 |
60 | ```csharp
61 | public record Person(string Name, DateTime BirthDate);
62 |
63 | var person = new Person("André Baltieri", DateTime.Now);
64 | ```
65 |
66 | Basta definir o tipo e nome das propriedades já na criação do `record`, como se fossem os parâmetros de um método e pronto.
67 |
68 | ## Tipagem com classe
69 | Por fim, se quiser utilizar o clássico, com todo poder que a OOP oferece, vale a pena ir de classes.
70 |
71 | ```csharp
72 | public class Person
73 | {
74 | public string Name { get; init; }
75 | public DateTime BirthDate { get; init; }
76 | }
77 |
78 | var person = new Person
79 | {
80 | Name = "André Baltieri",
81 | BirthDate = DateTime.Now
82 | };
83 | ```
84 |
85 | ## Conclusão
86 | Podemos trabalhar com tipos anônimos de forma simples e fácil no C#, sem a necessidade de criar classes, estruturas ou registros.
--------------------------------------------------------------------------------
/como-testar-o-dotnet-8-e-csharp-12-hoje-mesmo/index.md:
--------------------------------------------------------------------------------
1 | Nas últimas semanas tivemos o lançamento do Preview 3 do .NET 8 que sai em Novembro de 2023, juntamente com as primeiras novidades do C# 12. Vamos testar isso tudo?
2 |
3 | ## Como instalar o .NET 8
4 |
5 | Você pode fazer o download do .NET 8 no site oficial da Microsoft, utilizando a URL abaixo.
6 |
7 | 🔗 [https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
8 |
9 | Como o C# é uma linguagem gerenciada, e no caso, gerenciada pelo .NET, sua versão acompanha o Framework.
10 |
11 | Desta forma, para utilizar o C# 12, você precisa do .NET 8, para usar o C# 11 precisa do .NET 7, o 10 do 6 e assim por diante.
12 |
13 | # Language Preview
14 |
15 | É importante salientar que este recuso está disponível no .NET 8 Preview 3, ou seja é apenas uma pré-visualização do que poderá ser este recurso.
16 |
17 | Já vimos casos no passado, como o !! que foram removidos da versão final, então não se apegue muito aos novos recursos em sí até a versão final.
18 |
19 | É importante frisar também que o .NET 8 só sai em Novembro de 2023, muita coisa pode mudar até lá e você precisa instalar a versão Preview 3 ou superior para testar estas funcionalidades.
20 |
21 | O Language Preview é uma configuração contida no CSPROJ que diz qual versão do C# será usado no projeto.
22 |
23 | Podemos utilizar este recurso tanto para aumentar como diminuir as versões da linguagem, sempre respeitando o Framework em pauta.
24 |
25 | Se você está usando .NET 6 por exemplo, pode usar o C# 10 ou inferior, mas nunca superior.
26 |
27 | Por fim, é importante entender que o C# também é distribuído em diferentes versões e somente ter o .NET 8 como Target Framework não significa que estamos usando a última versão.
28 |
29 | É preciso de uma configuração adicional como veremos aqui neste artigo.
30 |
31 | ## Verificando a versão instalada
32 |
33 | Com o .NET instalado, basta fechar seus terminais e abrir novamente, seguido pela execução do comando abaixo para verificar a versão instalada.
34 |
35 | ```bash
36 | dotnet --version
37 | ## 8.0.100-preview.3.23178.7
38 | ```
39 |
40 | Além disso, o .NET 8 ainda mantém o C# 11 como linguagem padrão, então é preciso habilitar uma funcionalidade chamada **Language Preview** no arquivo `.csproj` do seu projeto.
41 |
42 | ## Habilitando o Language Preview
43 |
44 | Isto é feito pela configuração chamada **LangVersion** cujo temos que atribuir o valor `preview`, como mostrado abaixo.
45 |
46 | ```xml
47 |
48 |
49 |
50 | Exe
51 | net8.0 👈 Garantir que o .NET está na V8
52 | enable
53 | enable
54 | preview 👈 Adiciona esta linha
55 |
56 |
57 |
58 | ```
59 |
60 | Além disso, provavelmente sua IDE não vai reconhecer os comandos novos, identificando eles como possíveis erros.
61 |
62 | 
63 |
64 | Mas o Build não mente, e como podemos ver, mesmo com a IDE informando que a sintacxe não é válida, nosso programa compila corretamente.
65 |
66 | # Conclusão
67 |
68 | Trocar de versão de linguagem e Framework no .NET é um trabalho relativamente simples, só precisamos nos atentar em relação as Breaking Changes e funcionalidades específicas de cada versão.
69 |
--------------------------------------------------------------------------------
/csharp-as-is/index.md:
--------------------------------------------------------------------------------
1 | Junto ao C# 10 chegaram dois novos operadores, AS e IS para complementar a família e salvar algumas linhas de código dos nossos sistemas.
2 |
3 | ## Operador IS
4 | O `is` é um operador de comparação, que podemos utilizar para comparar tipos tanto primitivos quanto complexos, eliminando a necessidade do `typeof`, até então presente como única opção.
5 |
6 | ```csharp
7 | var someText = "This is a string";
8 |
9 | // Retorna um bool
10 | var result = someText.GetType() == typeof(string);
11 | ```
12 |
13 | No exemplo acima, utilizamos o `GetType` para obter o tipo de uma variável e em seguida comparamos ela com algum outro tipo utilizando o `typeof`. Como retorno temos um `bool` informando se a variável é ou não do tipo comparado.
14 |
15 | Embora seja uma expressão simples e fácil de entender, podemos substituí-la pelo `is`, tornando o código ainda mais simples e elegante, como podemos ver abaixo.
16 |
17 | ```csharp
18 | var result = someText is string;
19 | ```
20 | ### Comparando tipos complexos
21 | O `is` funciona para tipos complexos também, como `class` ou `record`, e para exemplificar vamos criar alguns registros que identificam documentos, como CPF, CNPJ e Passaporte.
22 |
23 | ```csharp
24 | public record Documento { ... }
25 | public record CPF : Document { ... }
26 | public record CNPJ : Document { ... }
27 | ```
28 |
29 | Como podemos notar, os documentos CPF, CNPJ e Passaporte, derivam de uma classe base chamada pagamento. Se ficou confuso esta parte, confere nosso [**CURSO DE ORIENTAÇÃO A OBJETOS**](https://balta.io/cursos/fundamentos-orientacao-objetos) com C# que tem tudo nos detalhes lá.
30 |
31 | ```csharp
32 | var p = new Passaporte();
33 | if (p is Documento)
34 | Console.WriteLine("P é um documento");
35 | ```
36 |
37 | Da mesma forma, podemos aplicar uma comparação aos objetos utilizando o comparador `is` como exemplificado na linha `p is Documento`. O código fica bem mais legível.
38 |
39 | ### Utilizando IS na comparação de nulos
40 | Talvez um dos cenários que vejo mais uso para o `is` seja na comparação de objetos com `null`, tanto para verificar se é nulo ou não é nulo. Vamos conferir a mudança olhando um código sem uso do `is`.
41 |
42 | ```csharp
43 | if(student == null)
44 | Console.WriteLine("Nulo");
45 |
46 | if(student != null)
47 | Console.WriteLine("Não Nulo");
48 | ```
49 | Este mesmo código funcionaria apenas aplicando o `is` ou `is not` na comparação, algo sutil a nível de código mas que traz uma legibilidade infinitamente maior.
50 |
51 | ```csharp
52 | if(student is null)
53 | Console.WriteLine("Nulo");
54 |
55 | if(student is not null)
56 | Console.WriteLine("Não Nulo");
57 | ```
58 |
59 | ## Operador AS
60 | Outro operador útil que pode melhorar bastante a legibilidade do código é o `as`, para fazer conversões explícitas de objetos. É comum vermos o uso do tipo em frente a variável, utilizando parênteses para fazer a conversão, como mostrado abaixo.
61 |
62 | ```csharp
63 | var documento = new Documento();
64 | var cpf = (CPF)documento;
65 | ```
66 |
67 | Porém, podemos fazer esta conversão de uma forma bem mais elegante utilizando `as` ao invés de `(CPF)` como mostrado no exemplo anterior.
68 |
69 | ```csharp
70 | var documento = new Documento();
71 | var cpf = documento as CPF;
72 | ```
73 |
74 | ## Conclusão
75 | Com dois operadores novos e simples, o `is` e `as` podemos melhorar muito o nosso código, entregando uma melhor legibilidade e facilitando o entendimento.
--------------------------------------------------------------------------------
/dotnet-platform-specific/index.md:
--------------------------------------------------------------------------------
1 | O .NET suporta diferentes plataformas como Windows, Mac e Linux, mas você sabe como criar um código específico para uma delas?
2 |
3 | ## OperatingSystem
4 | O .NET 6 traz ainda mais plataformas para ampliar o leque, contando com iOS, Android, MacCatalyst e muito mais.
5 |
6 | Isto nos permite criar sistemas para múltiplas plataformas com o mesmo **codebase** e muitas vezes sem precisar alterar nada do código.
7 |
8 | Porém, em alguns casos queremos executar determinadas ações somente em uma (Ou mais de uma) plataforma específica, e para isto temos o `OperatingSystem`, um enumerador que podemos indagar sobre qual SO estamos utilizando.
9 |
10 | ```csharp
11 | if (OperatingSystem.IsWindows())
12 | Console.WriteLine("Estou no Windows");
13 |
14 | if (OperatingSystem.IsMacOS())
15 | Console.WriteLine("Estou no Mac");
16 | ```
17 |
18 | O `OperatingSystem` tem todos as plataformas suportadas pelo .NET e futuras plataformas, quando adicionadas, também serão visíveis aqui.
19 |
20 | ## SupportedOSPlatform
21 | Além do `OperatingSystem` podemos utilizar o atributo `SupportedOSPlatform` que adiciona um **warning** a nível de compilação dizendo que um método só pode se executado em determinadas plataformas.
22 |
23 | Algumas IDEs como o JetBrain Raider e Visual Studio já interpretam este alerta e notificam em tempo de escrita que a chamada ao método é inválida.
24 |
25 | Em caso de invocação de um método não suportado pela plataforma atual, o **warning** abaixo será exibido.
26 |
27 | ```
28 | warning CA1416: This call site is reachable on all platforms. 'CustomFileWriter.WindowsOnly()' is only supported on: 'windows'.
29 | ```
30 |
31 | Neste exemplo estou no Mac e criei um método com atributo `SupportedOSPlatform` informando que o mesmo só suporta a plataforma **Windows**, como mostrado abaixo.
32 |
33 | ```csharp
34 | using System.Runtime.Versioning;
35 |
36 | [SupportedOSPlatform("windows")]
37 | public void WindowsOnly()
38 | {
39 | //...
40 | }
41 | ```
42 |
43 | ### Suportando múltiplas plataformas
44 | O atributo `SupportedOSPlatform` é cumulativo, o que significa que podemos suportar diferentes plataformas em um mesmo atributo, como mostrado no exemplo abaixo.
45 |
46 | ```csharp
47 | using System.Runtime.Versioning;
48 |
49 | [SupportedOSPlatform("windows"), SupportedOSPlatform("macos")]
50 | public void WindowsAndMac()
51 | {
52 | }
53 | ```
54 | Por fim, aqui vai o exemplo completo, suportando **Mac**, **Windows** e ambos. Infelizmente não existe um enumerador com o nome das plataformas, é preciso informá-las como `string`, o que pode conter erros.
55 |
56 | ```csharp
57 | using System.Runtime.Versioning;
58 |
59 | public class CustomFileWriter
60 | {
61 | [SupportedOSPlatform("windows")]
62 | public void WindowsOnly()
63 | {
64 | }
65 |
66 | [SupportedOSPlatform("macos")]
67 | public void MacOnly()
68 | {
69 | }
70 |
71 | [SupportedOSPlatform("windows"), SupportedOSPlatform("macos")]
72 | public void WindowsAndMac()
73 | {
74 | }
75 | }
76 | ```
77 |
78 | ## Conclusão
79 | O .NET suporta múltiplas plataformas e embora possamos escrever a maior parte do código de forma bem genérica, alguns pontos ainda precisam ser específicos, então podemos fazer uso do `OperatingSystem` e `SupportedOSPlatform` para resolver este problema.
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/csharp-action/index.md:
--------------------------------------------------------------------------------
1 | As Actions no C# funcionam como uma espécie de delegate onde podemos armazenar ações para serem executadas posteriormente.
2 |
3 | ## Action
4 | Um `Action` no C# é um tipo que pode receber uma função. Existe também o `Func` que falaremos nos próximos artigos aqui.
5 |
6 | Para definir uma `Action` basta criar seu tipo e apontar para uma função seja no momento da declaração da variável ou posteriormente.
7 |
8 | ```csharp
9 | Action acao;
10 |
11 | acao = MinhaFuncao;
12 |
13 | acao();
14 |
15 | void MinhaFuncao()
16 | {
17 | Console.WriteLine("Eu sou uma função");
18 | }
19 | ```
20 |
21 | No exemplo acima, temos uma função chamada `MinhaFuncao` que imprime um texto na tela. Após definida, podemos criar uma ação como definimos em `Action acao` e depois assimilar a função a esta ação, como fizemos com `acao = MinhaFuncao`.
22 |
23 | Por fim podemos executar esta ação invocando-a, como fazemos com qualquer função (Abrindo e fechando parênteses) desta forma `acao();`.
24 |
25 | ## Funções anônimas
26 |
27 | Dada uma função que não recebe parâmetros (Parameterless), podemos assimilá-la diretamente a um `Action` como fizemos anteriormente em `acao = MinhaFuncao;`.
28 |
29 | Porém quando temos parâmetros, a invocação da função exige os mesmos, e neste caso, precisamos da assinatura completa da função para poder invocá-la posteriormente.
30 |
31 | Isto pode ser feito utilizando as funções anônimas do C#, cujo podem ser definidas como `() =>` e são exemplificadas abaixo.
32 |
33 | ```csharp
34 | Action acao;
35 |
36 | acao = () => MinhaFuncao("Eu sou um parâmetro");
37 |
38 | acao();
39 |
40 | void MinhaFuncao(string texto)
41 | => Console.WriteLine(texto);
42 | ```
43 |
44 | Note que neste caso, é como se estivessemos executando a função, podemos passar os parâmetros necessários para ela ser executada, tudo conforme estamos acostumados já no C#.
45 |
46 | Porém, a execução desta função não será realizada no momento que associamos ela com a `Action` e sim na hora que executamos a `Action`, neste caso a linha `acao();`.
47 |
48 | ## Action Chaining
49 | Mas qual a vantagem em ter uma função que armazena uma função? Bem, uma delas é o **Action Chaining** ou encadeamento de funções.
50 |
51 | Em diversas conversas durante os [**Encontros Premium**](https://balta.io/agenda) eu mostrei alguns exemplos de como usamos CQRS aqui no balta e como temos uma cadeia de eventos que acontecem em uma ordem específica.
52 |
53 | Vamos tomar como base um cadastro de novos clientes/alunos, com os seguintes métodos abaixo.
54 |
55 | ```csharp
56 | Action handle;
57 |
58 | handle = VerificaRequisicao;
59 | handle += VerificaSeEmailEstaEmUso;
60 | handle += GeraOUsuario;
61 | handle += GeraOAluno;
62 | handle += PersisteOsDados;
63 | handle += EnviaCodigoDeAtivacao;
64 | handle += LogaANovaContaCriada;
65 |
66 | handle();
67 |
68 | void VerificaRequisicao() { }
69 | void VerificaSeEmailEstaEmUso() { }
70 | void GeraOUsuario() { }
71 | void GeraOAluno() { }
72 | void PersisteOsDados() { }
73 | void EnviaCodigoDeAtivacao() { }
74 | void LogaANovaContaCriada() { }
75 | ```
76 |
77 | Neste caso, podemos utilizar o `+=` para anexar funções ao `Action` e posteriormente executá-las na ordem que foram atribuídas.
78 |
79 | Utilizamos este modelo por conta do reuso das funções em diversas partes do sistema. Imagina uma simples validação de E-mail, queremos saber se o E-mail já está cadastrado em nossa base, então isto vira uma função que pode ser invocada em diferentes `Handlers`.
80 |
81 | ## Conclusão
82 | O C# permite criarmos ações ou cadeia delas para serem executadas posteriormente. Isto permite uma maior reusabilidade das funções e alocação dinâmica das mesmas.
83 |
84 |
85 |
--------------------------------------------------------------------------------
/windows-11-instalacao/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Como instalar o Windows 11 - Preview
3 | published: true
4 | description: Tentou atualizar seu Windows 10 para o Windows 11 e não conseguiu? Veja aqui algumas possíveis soluções
5 | tags:
6 | cover_image: https://res.cloudinary.com/practicaldev/image/fetch/s--4bSQExND--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j92u9sxuxxy5egc9jyat.png
7 | ---
8 |
9 | 
10 |
11 | ## Windows Insider
12 | A primeira versão do Windows 11 está disponível desde 27/06 para membros do [**Windows Insider**](https://insider.windows.com/pt-br/), então seu primeiro passo é se cadastrar lá.
13 |
14 | O cadastro é simples e não requer nenhum pagamento, basta associar uma conta Microsoft com sua conta "Insider".
15 |
16 | ## Ligando sua conta Microsoft ao Windows
17 | No seu Windows 10 atual, vá para as configurações e busque por "Minha conta" ou "Account Info". Nesta tela, você poderá linkar sua conta Microsoft com seu computador (Windows).
18 |
19 | ## Habilitando o Windows Insider
20 | Ainda nas configurações, procure por **Windows Insider** e na tela desta configuração haverão três opçÕes:
21 | * Updates convencionais
22 | * Betas e Previews
23 | * Dev
24 |
25 | Informações sobre o Windows 11 já devem aparecer nas duas últimas opções.
26 |
27 | ### IMPORTANTE
28 | As releases beta, preview e dev não são estáveis ou seja, não são recomendadas para produção. Use por sua conta e risco.
29 |
30 | No meu caso, utilizo a **Dev**, mas recomendo que se é seu primeiro contato com o Insider, vá de Beta/Preview.
31 |
32 | ## TPM 2.0
33 | Nestas primeiras previews do Windows 11, muitas pessoas tem recebido a seguinte mensagem:
34 |
35 | 
36 |
37 | Na maioria dos casos ela se refere ao chip TPM 2.0 utilizado para encriptação de informações, que vem presente em diversas placas mãe/processadores desde 2016.
38 |
39 | Para verificar se você está com o TPM habilitado, execute o seguinte comando no **Run** (Win + R):
40 | `tpm.msc`
41 |
42 | Caso receba uma mensagem negativa, não significa que você não tem este chip, mesmo que a mensagem diga explicitamente isto.
43 |
44 | No meu caso, mesmo com uma configuração atual como a abaixo, eu estava recebendo esta mensagem:
45 | 
46 |
47 | ## Habilitando o TPM 2.0
48 | Aqui é a parte mais chata, pois a configuração do TPM 2.0 fica em lugares diferentes na **BIOS**, então pode variar de acordo com cada configuração.
49 |
50 | No meu caso, ela fica em **Advanced Options** > **fTPM**, e ela já aparecia como **Enabled**, o que fiz foi mudar a opção de qual TPM utilizar para **Firmware**.
51 |
52 | Acredito que na maioria dos CPUs Ryzen (AM4) esta configuração deve ser parecida. Então recorra ao manual ou ao amigo Google e depois repita o processo do `tpm.msc` para ver se está tudo certo.
53 |
54 | ## Instalando o Windows 11
55 | Feito isto, tudo pronto, você verá uma atualização para o Windows 11 que é bem "grandinha" por sinal.
56 |
57 | Durante a atualização foi tudo tranquilo aqui, e até o momento estou no Windows 11 sem nenhum problema.
58 |
59 | ## Futuras Builds
60 | Todo este processo de habilitar o TPM provavelmente será modificado, pois um usuário comum não teria condições de executar estes procedimentos.
61 |
62 | Temos que lembrar que estes Previews são focados em um público mais técnico mesmo, então não precisam se preocupar, a transição do Windows 10 para o Windows 11 provavelmente vai ser tão tranquila quanto as anteriores.
--------------------------------------------------------------------------------
/csharp-11-o-que-vem-por-ai/index.md:
--------------------------------------------------------------------------------
1 | Neste artigo vamos conferir as primeiras novidades e mudanças anunciadas para o C# 11, presente no .NET 7, que será lançado em Novembro de 2022.
2 |
3 | ## O que vem por aí?
4 | Semana passada, Kathleen Dollard, a Program Manager do C#, liberou um [post com um Preview](https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/) das primeiras novidades do C# 11, e vamos conferir neste artigo algumas delas.
5 |
6 |
7 | ## Como testar o Preview?
8 | Para testar estas funcionalidades, você precisa editar seu arquivo `csproj` e adicionar a chave `preview` a ele, como mostrado abaixo.
9 |
10 | ```xml
11 |
12 |
13 | Exe
14 | net6.0
15 | enable
16 | enable
17 | preview
18 |
19 |
20 | ```
21 |
22 | ## Quebra de linha na interpolação de strings
23 | No C# podemos utilizar o caractere `$` antes de uma `string` para permitir sua interpolação. O mesmo acontece com a necessidade de quebra de linhas dentro da `string` que demanda o caractere `@` antes da mesma.
24 |
25 | ```csharp
26 | var inter = $"eu sou uma string {valor}";
27 | var quebra = @"eu posso
28 | quebrar linhas";
29 | var osDois = $@"eu interpolo {valores} e
30 | ainda quebro linhas";
31 | ```
32 |
33 | Note que precisamos utilizar `$@` juntos para obter o resultado esperado. No C# 11, isto poderá ser feito diretamente na interpolação de `string`, apenas usando `$`.
34 |
35 | ```csharp
36 | var v = $"Count ist: { this.Is.Really.Something()
37 | .That.I.Should(
38 | be + able)[
39 | to.Wrap()] }.";
40 | ```
41 |
42 | ## List patterns
43 | Outra mudança bem-vinda é o **List Patterns** ou padrões de listas, algo similar ao que temos em outras linguagens como JavaScript e que nos permite criar padrões utilizando `...`.
44 |
45 | ```csharp
46 | int[] arr1 = { 1, 2, 5, 6, 7, 8, 9, 10 };
47 |
48 | public static int CheckSwitch(int[] values)
49 | => values switch
50 | {
51 | [1, 2, .., 10] => 1, // Vai até o valor 10
52 | [1, 2] => 2,
53 | [1, _] => 3,
54 | [1, ..] => 4, // Vai do 1 ao fim da lista
55 | [..] => 50 // Vale para toda a lista
56 | };
57 | ```
58 |
59 | Ainda podemos capturar parte de uma lista, como mostrado abaixo utilizando `var middle` que no caso recebeu a **fatia** da lista.
60 |
61 | ```csharp
62 | public static string CaptureSlice(int[] values)
63 | => values switch
64 | {
65 | [1, .. var middle, _] => $"Middle {String.Join(", ", middle)}",
66 | [.. var all] => $"All {String.Join(", ", all)}"
67 | };
68 | ```
69 |
70 | ## Null Checking
71 | Outra mudança é a checagem de nulos, que já havia sido melhorada nas versões anteriores com uso do `is`, como mostrado abaixo:
72 |
73 | ```csharp
74 | public static void M(string s)
75 | {
76 | if (s is null)
77 | {
78 | throw new ArgumentNullException(nameof(s));
79 | }
80 | // Body of the method
81 | }
82 | ```
83 |
84 | Porém, no C# 11, teremos a inclusão do **double bang** `!!`, que impede a passagem de um valor nulo ao parâmetro, tornando assim dispensável a checagem por nulos.
85 |
86 | ```csharp
87 | public static void M(string s!!)
88 | {
89 | // Body of the method
90 | }
91 | ```
92 |
93 | ## Conclusão
94 | O C# vem se modernizando a cada versão, melhorando performance e se aproximando de linguagens mais "moderninhas". E você, está empolgado com esta nova versão que chega em Novembro deste ano?
--------------------------------------------------------------------------------
/data-driven-vs-domain-driven/index.md:
--------------------------------------------------------------------------------
1 | Recentemente publiquei um vídeo, no canal do balta.io no YouTube, onde [criamos uma API com ASP.NET Core 3 e EF Core 3 em menos de 15 minutos](https://www.youtube.com/watch?v=but7jqjopKM).
2 |
3 | Claro que é apenas uma demo, e ainda faltam recursos na API como versionamento, cache, compressão, documentação entre outros, mas se levarmos em conta que no fim temos um cadastro de produtos com categorias, em menos de 15 minutos, é algo de se pensar.
4 |
5 | Data Driven
6 | -----------
7 |
8 | Em alguns vídeos sobre testes de unidade, eu comento que se você “perder tempo” testando a coisa errada, como por exemplo tamanho de campo e outros itens que não são regras de negócio, você terá BEM MENOS tempo para testar o que realmente importa.
9 |
10 | Isto é um fato, e algo que assombra muitos projetos que passo, onde o pessoal diz não ter tempo para testar, mas na verdade estão dedicando esforços no lugar errado.
11 |
12 | Se não tem regra de negócio, talvez a melhor escolha seja o modelo Data Driven, que nada mais é do que um “espelho” do banco de dados, ou seja, o famoso CRUD.
13 |
14 | Se não tem regras, não necessitamos de tantos testes, nem de tanto esforço no domínio. Não é interessante ficar implementando classes, herança, interfaces e várias outras coisas da OOP/SOLID/Clean Code em um cadastro de categoria, de unidade de medida, de estado civil por exemplo.
15 |
16 | Seja simples e objetivo no seu código, e se for partir para o modelo Data Driven, minha recomendação é a do vídeo no começo deste artigo, simplesmente criar os modelos, adicionar os Data Annotations e mandar bala! Gerar as migrações, publicar e pronto, API no ar!
17 |
18 | Domain Driven
19 | -------------
20 |
21 | O famoso DDD, onde você vai utilizar tudo que aprendeu sobre OOP, SOLID, Clean Code, padrões e muito mais.
22 |
23 | O DDD funciona quando temos regras de negócio, quando temos domínios mais ricos. Aplicar ele em projetos onde você não tem estes requisitos é suicídio.
24 |
25 | Imagine um projeto onde você precisa executar cálculos de impostos por exemplo, algo que não pode errar. Com certeza é um cenário para você trabalhar bem no domínio, nas entidades e nos testes de unidade.
26 |
27 | Muita gente confunde o uso do DDD com tamanho do projeto. As vezes seu projeto pode ser grande, mas todo orientado a dados, sem regras complexas de negócio. Isto não justifica o uso do DDD.
28 |
29 | Então dada a complexidade do seu domínio, aí sim é definido o uso de DDD ou não.
30 |
31 | Por que não os dois juntos?
32 | ---------------------------
33 |
34 | Em diversos projetos que passo a primeira coisa que fazemos é analisar o contexto e domínio da aplicação, em boa parte dos cenários, mais de 50% da aplicação é apenas CRUD, ou sejam, apenas cadastro básicos.
35 |
36 | Em um dos últimos projetos que participei recentemente, no fim da análise, chegamos a conclusão que 72% da aplicação eram cadastros básicos, como os que citei, de categoria, unidade de medida e por aí vai, sem regras de negócio.
37 |
38 | O que fizemos? Em um dia e meio geramos todos os CRUDs via T4 Templates, já com as Views em um projeto separado. Ou seja, em um dia e meio tínhamos mais de 70% do projeto concluído.
39 |
40 | Com este andamento, ainda sobraram 3 meses de projeto, para aí sim o time focar em DDD, SOLID, Clean Code, criar testes de unidade, trabalhar com calma no que realmente importava.
41 |
42 | Conclusão
43 | ---------
44 |
45 | One size doesn\`t fits all (Um tamanho não serve para tudo), ou seja, assim como Data Driven não resolve tudo, DDD também não. E por que não utilizar o melhor dos dois? Fazemos isto com Dapper e EF por exemplo.
46 |
47 | A estratégia certa na criação do projeto é o que define o sucesso dele. Pensar fora da caixa, entender que não existe bala de prata, são coisas fundamentais para garantir entregas concisas e de valor.
--------------------------------------------------------------------------------
/exception-vs-domain-notification/index.md:
--------------------------------------------------------------------------------
1 | Então você precisa validar suas entidades de domínio e tem duas opções. Talvez a mais clara seria utilizar Exceptions, mas será que ela é a melhor escolha?
2 |
3 | Neste artigo vamos abrir espaço para o eterno debate sobre Exceptions VS Domain Notifications e vou colocar alguns motivos nos quais utilizo Domain Notifications nas validações do meu domínio.
4 |
5 | ### O que é uma Exception?
6 |
7 | Uma exceção oras, algo que não deveria acontecer mas aconteceu, algo quase que imprevisível.
8 |
9 | ### O que é um Domain Notification
10 |
11 | Uma notificação, uma mensagem sobre algum acontecimento no seu domínio.
12 |
13 | ### O que acontece quando temos uma Exception?
14 |
15 | Sua execução é parada e o evento ocorrendo no momento é gravado no Event Viewer (Caso do IIS).
16 |
17 | É gerado um alarde maior, como se fosse um erro na sua aplicação e temos um custo maior, afinal logamos tudo nos eventos do host.
18 |
19 | ### Devo parar de usar Exceptions?
20 |
21 | Não! As exceções tem seu uso. Por exemplo, se você não consegue se conectar ao banco de dados, adianta prosseguir com o request? Este é um belo exemplo em que devemos utiliza-las.
22 |
23 | ### Devo utiliza-las no Domínio?
24 |
25 | Depende! Em tese eu não vejo um cenário onde por exemplo teria uma conexão ao banco no meu domínio.
26 |
27 | Juntando isto com o fato da interrupção da execução e do log dos eventos, acaba complicando seu uso.
28 |
29 | Imagine um cenário onde você estoura uma exceção no cadastro de clientes, no momento em que valida seu documento por exemplo (Afinal, não podemos salvar um cliente com documento inválido).
30 |
31 | Em primeiro lugar, se esta fosse a primeira das suas N validações, seu fluxo seria interrompido aí, acarretando no retorno pra tela, o que incomodaria bastante o usuário, pois fica aquela validação picada. Corrige documento, nome errado corrige nome, data de nascimento errado, e por aí vai.
32 |
33 | Em adicional, esta exceção, como comentei anteriormente, consumiria mais recursos, pelo fato de logar nos eventos da máquina, no caso, mais recursos de disco.
34 |
35 | Agora imagina um cenário com milhões de cadastros? Ou um simples Brute Force ali, seria o bastante pra lotar a máquina.
36 |
37 | Desta forma, quase nunca utilizo Exceptions no meu domínio. Utilizo Notification Pattern, com Flunt.
38 |
39 | [Repositório do Flunt](https://github.com/andrebaltieri/flunt)
40 |
41 | ### Fail Fast Validations
42 |
43 | Outra abordagem que utilizo são os Fail Fast Validations, onde faço uma validação inicial nos meus Commands, removendo possíveis validações bestas das minhas entidades e não sobrecarregando elas. Afinal, partimos do princípio que as informações devem ao menos chegar as entidades.
44 |
45 | ### Testes de Unidade
46 |
47 | Trazer a regra de negócio para seu domínio tem um motivo: Testes de Unidade! Se você brigou tanto com o DBA pra sair das PROCS e não faz testes, não adianta nada.
48 |
49 | É possível testarmos por exeções (ExpectedException), mas elas são mais falhas, pois se você espera uma exceção do tipo ArgumentNullException no Name do Customer e ocorre uma outra exceção do tipo ArgumentNullException no Email do Customer, seu teste vai dar falso positivo.
50 |
51 | ### Curso 1975
52 |
53 | Tem mais um mundo de coisas que eu poderia escrever aqui, mas falei tanto sobre isto que até transformei em um curso, o 1975 - Modelando Domínios Ricos, que está gratuito no balta.io.
54 |
55 | [1975 - Modelando Domínios Ricos](https://balta.io/cursos/1975)
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/mongodb-docker/index.md:
--------------------------------------------------------------------------------
1 | Neste artigo vamos aprender a utilizar o MongoDb via Docker, dispensando a necessidade de um serviço sempre em execução na sua máquina de desenvolvimento.
2 |
3 | ## Requisitos
4 |
5 | ### Terminal
6 | Se estiver no Mac ou Linux, provavelmente já tem um Terminal bacana, mas caso esteja utilizando o Windows, sugiro fortemente que utilize o **Windows Terminal** para estas ações.
7 |
8 | Aqui tem um link com a instalação e configurações que uso:
9 | [https://balta.io/blog/windows-terminal](https://balta.io/blog/windows-terminal)
10 |
11 | ## Docker
12 |
13 | Você precisa também do **Docker** instalado e rodando em sua máquina. Caso ainda não tenha realizado esta instalação, aqui está um artigo que mostro como fazer: [https://balta.io/blog/docker-instalacao-configuracao-e-primeiros-passos](https://balta.io/blog/docker-instalacao-configuracao-e-primeiros-passos)
14 |
15 | ### WSL 2 (Somente Windows)
16 | Caso esteja no Windows, recomendo fortemente que instale e utilize o **WSL** que é um subsistema Linux dentro do Windows.
17 |
18 | Este processo tem que ser feito **antes** da instalação do Docker.
19 | Basta acessar este link e realizar a instalação: [https://balta.io/blog/wsl](https://balta.io/blog/wsl)
20 |
21 | ## Obtendo a imagem
22 |
23 | Certifique-se que o Docker está em execução e abra um novo terminal, no meu caso, a versão do Docker em execução é a mostrada abaixo. Você pode verificar isto executando o comando docker --version no seu terminal.
24 |
25 | ```
26 | Docker version 19.03.12, build 48a66213fe
27 | ```
28 |
29 | Nosso primeiro passo então é obter a imagem do Mongo que será o molde para criarmos nossos containers. Para isto, executamos o comando abaixo.
30 |
31 | ```
32 | docker pull mongo
33 | ```
34 |
35 | Note que a primeira mensagem será Using default tag: latest o que significa que estamos obtendo a última versão desta imagem, provavelmente com a última versão estável do Mongo.
36 |
37 | Caso queira baixar alguma versão específica, verifique as [tags disponíveis aqui](https://hub.docker.com/_/mongo?tab=tags).
38 |
39 | ## Rodando o Mongo
40 |
41 | Para executar esta imagem você pode usar a linha abaixo. Não se esqueça de mudar o MONGO_INITDB_ROOT_USERNAME e MONGO_INITDB_ROOT_PASSWORD para o usuário e senha desejado.
42 |
43 | ```
44 | docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=balta -e MONGO_INITDB_ROOT_PASSWORD=e296cd9f mongo
45 | ```
46 |
47 | ### Windows
48 |
49 | Caso esteja no Windows, com **WSL 2** é importante informar o volume onde este container será executado, utilizando a flag -v ~/docker como mostrado abaixo.
50 |
51 | ```
52 | docker run -v ~/docker --name mongodb -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=balta -e MONGO_INITDB_ROOT_PASSWORD=e296cd9f mongo
53 | ```
54 |
55 | Para parar a execução você pode pressionar CTRL + C no Terminal. Deste momento em diante, seu container vai aparecer na **Dashboard** do Docker de forma visual, onde você poderá parar ou iniciar ela a qualquer momento.
56 |
57 | ## Connection String
58 |
59 | Se você utilizou as mesmas configurações deste artigo, sua **Connection String** será igual abaixo. Caso necessário, modifique as informações que alterou na execução dos containers.
60 |
61 | ```
62 | mongodb://balta:e296cd9f@localhost:27017/admin
63 | ```
64 |
65 | ### GUI Client
66 |
67 | Caso queira gerenciar seu banco de uma forma visual, você pode utilizar uma das ferramentas gratuitas abaixo:
68 |
69 | * [MongoDb Compass](https://www.mongodb.com/try/download/compass)
70 |
71 | ## Erros comuns
72 |
73 | ### Authentication Failed
74 | Alguns casos podem apresentar erro de autenticação, principalmente em bancos que não sejam o admin.
75 |
76 | Para adicionar um novo usuário ao Mongo, execute os passos abaixo substituindo o `NOME_DO_BANCO` pelo nome do banco que deseja criar o acesso.
77 |
78 | Estes passos precisam ser executados em um terminal com acesso ao Docker, assim como nos passos anteriores.
79 |
80 | ```
81 | docker exec mongo
82 |
83 | db.createUser(
84 | {
85 | user: "balta",
86 | pwd: "baltaio",
87 | roles: [
88 | { role: "readWrite", db: "NOME_DO_BANCO" }
89 | ]
90 | })
91 | ```
92 |
--------------------------------------------------------------------------------
/aspnet-logger/index.md:
--------------------------------------------------------------------------------
1 | O ILogger, presente no .NET (Extensions), nos permite retornar informações sobre execução, erros e avisos dos nossos sistemas de forma simples e fácil.
2 |
3 | ## O que é o Logging?
4 | O Logging é uma API ou biblioteca presente no .NET (Extensions), do qual podemos utilizar para "escrever" alguma mensagem durante a execução do nosso código.
5 |
6 | Existem várias bibliotecas de Logging, como NLog, Log4Net e Serilog, que fazem o mesmo trabalho, porém a padrão que vem nos templates da Microsoft é o `ILogger`.
7 |
8 | ### Instalação
9 | A maioria dos templates vem com este pacote instalado, mas caso o seu projeto não possua a dependência, a mesma fica no `Microsoft.Extensions`.
10 |
11 | ```
12 | dotnet add package Microsoft.Extensions
13 | ```
14 |
15 | Este pacote proverá o namespace `Microsoft.Extension.Logging` que possui os três itens que utilizaremos aqui, `ILogger`, `ILoggerFactory`, e `ILoggingProvider`.
16 |
17 | ## ILoggerFactory
18 | O `ILoggerFactory` é a interface da qual podemos criar as instâncias do `ILogger` e `ILoggingProvider`. Ela funciona como um facilitador para registrarmos e acessarmos os **loggers** de forma mais fácil.
19 |
20 | Por definição o `ILoggerFactory` possui apenas dois métodos, o `CreateLogger` que serve para criarmos um novo **logger** (Uma categoria para nossos logs) e o `AddProvider` que nos permite registrar outros provedores.
21 |
22 | ```csharp
23 | public interface ILoggerFactory : IDisposable
24 | {
25 | ILogger CreateLogger(string categoryName);
26 | void AddProvider(ILoggerProvider provider);
27 | }
28 | ```
29 |
30 | ## ILoggerProvider
31 | O `ILoggerProvider` server para criarmos instâncias específicas dos loggers por categoria. Ele possui apenas um método chamado `CreateLogger` que recebe e cria um segmento de logs.
32 |
33 | ```csharp
34 | public interface ILoggerProvider : IDisposable
35 | {
36 | ILogger CreateLogger(string categoryName);
37 | }
38 | ```
39 | Porém, o `ILoggerProvider` do `Microsoft.Extensions` já possui vários provedores **built-in**, como:
40 | * Console Provider
41 | * Debug Provider
42 | * EventSource Provider
43 | * EventLog Provider (Windows)
44 | * TraceSource Provider
45 |
46 | Caso queira criar seu próprio logger basta implementar a interface `ILoggerProvider`.
47 |
48 | ## Utilizando o ILogger
49 | Para utilizar o `ILogger` precisamos de uma instância do mesmo, e ela é dada através da class `ILogger`, onde `T` normalmente é a própria classe.
50 |
51 | Vamos tomar como base este exemplo abaixo, retirado do template padrão do ASP.NET MVC, onde temos uma instância do `ILogger` dentro do `HomeController`.
52 |
53 | ```csharp
54 | private readonly ILogger _logger;
55 | ```
56 | Com a variável definida, podemos exigir sua instância via construtor (DI), e a biblioteca de log já fará a instância do mesmo.
57 |
58 | ```csharp
59 | public HomeController(ILogger logger)
60 | => _logger = logger;
61 | ```
62 | Para logar alguma informação, basta utilizar o método `LogInformation` que a mesma será exibida no **Console**, durante a execução da aplicação.
63 |
64 | ```csharp
65 | public IActionResult Index()
66 | {
67 | _logger.LogInformation("Estou no Index do HomeController");
68 | return View();
69 | }
70 | ```
71 | Como resultado, temos o seguinte texto sendo exibido durante a execução da aplicação. Note a última linha contendo o texto que informamos no log anteriormente.
72 | ```
73 | dotnet run
74 |
75 | Building...
76 | info: Microsoft.Hosting.Lifetime[14]
77 | Now listening on: https://localhost:7244
78 | info: Microsoft.Hosting.Lifetime[14]
79 | Now listening on: http://localhost:5288
80 | info: Microsoft.Hosting.Lifetime[0]
81 | Application started. Press Ctrl+C to shut down.
82 | info: Microsoft.Hosting.Lifetime[0]
83 | Hosting environment: Development
84 | info: Microsoft.Hosting.Lifetime[0]
85 | Content root path: C:\dev\AspNetLoggerSample\
86 | info: AspNetLoggerSample.Controllers.HomeController[0]
87 | Estou no Index do HomeController
88 | ```
89 |
90 | ## Conclusão
91 | Neste primeiro artigo da série, pudemos ver como utilizar o `ILogger` padrão do .NET, mas ainda temos muitas coisas para especionar. Nos próximos capítulos veremos outras configurações e loggers.
--------------------------------------------------------------------------------
/aspnet-developer-roadmap/index.md:
--------------------------------------------------------------------------------
1 | * Foco em pragmatismo
2 | * Maior gap é no básico
3 |
4 | ## ASP.NET Developer Roadmap 2022
5 |
6 | ### Pré-requisitos
7 | * C#
8 | * .NET 6
9 | * Entity Framework
10 | * Dapper
11 | * NHibernate
12 | * ASP.NET Core
13 | * SQL Fundamentals
14 |
15 | ### Conhecimentos Gerais
16 | * Learn GIT, create a few repositories on GitHub, share your code with other people
17 | * Know HTTP(S) protocol, request methods (GET, POST, PUT, PATCH, DELETE, OPTIONS)
18 | * Don't be afraid of using Google, Power Searching with Google
19 | * Learn dotnet CLI
20 | * Read a few books about algorithms and data structures
21 |
22 | ### C#
23 | * Curso de Fundamentos
24 |
25 | ### SQL e Banco de Dados
26 | * Curso de Fundamentos
27 |
28 | ### ASP.NET
29 | * MVC
30 | * REST
31 | * Razor Pages
32 | * Razor Components
33 | * Middlewares
34 | * Filters & Attributes
35 | * Application Settings & Configurations
36 | * Authentication
37 | * Authorization
38 | * IdentityServer
39 | * Auth0
40 | * OIDC
41 |
42 | ### SOLID
43 | * Single Responsibility Principle (SRP)
44 | * Open-Closed Principle (OCP)
45 | * Liskov Substitution Principle (LSP)
46 | * Interface Segregation Principle (ISP)
47 | * Dependency Inversion Principle (DIP)
48 |
49 | ### ORM
50 |
51 | ### DI
52 | * Microsoft.Extensions.DependencyInjection
53 | * AutoFac
54 | * Ninject
55 | * Castle Windsor
56 | * Simple Injector
57 | * Life Cycles
58 | * Scrutor
59 |
60 | ### Cache
61 | * Memory Cache
62 | * Distributed Cache
63 | * Redis
64 | * StackExchange.Redis
65 | * EasyCaching
66 | * Memcached
67 | * Entity Framework 2nd Level Cache
68 | * EFCoreSecondLevelCacheInterceptor
69 | * EntityFrameworkCore.Cacheable
70 |
71 | ### Database
72 | * Relational
73 | * SQL Server
74 | * PostgreSQL
75 | * MariaDB
76 | * MySQL
77 | * Cloud Databases
78 | * CosmosDB
79 | * DynamoDB
80 | * Search Engines
81 | * ElasticSearch
82 | * Solr
83 | * Sphinx
84 | * NoSQL
85 | * Redis
86 | * MongoDB
87 | * Apache Cassandra
88 | * LiteDB
89 | * RavenDB
90 | * CouchDB
91 |
92 | ### Log
93 | * Log Frameworks
94 | * Serilog
95 | * NLog
96 | * Log Management System
97 | * ELK Stack
98 | * Sentry.io
99 | * Loggly.com
100 | * Elmah.io
101 |
102 | ### API
103 | * REST
104 | * OData
105 | * Sieve
106 | * gRPC
107 | * GraphQL
108 | * HotChocolate
109 | * GraphQL-dotnet
110 |
111 | ### Real Time
112 | * SignalR
113 | * WebSockets
114 |
115 | ### Object Mapping
116 | * AutoMapper
117 | * Mapster
118 | * ExpressMapper
119 | * AgileMapper
120 |
121 | ### Task Scheduling
122 | * Background Service
123 | * HangFire
124 | * Quartz
125 | * Coravel
126 |
127 | ### Testing
128 | * Unit Testing
129 | * Frameworks
130 | * xUnit
131 | * NUnit
132 | * MSTest
133 | * Mocking
134 | * Moq
135 | * NSubstitute
136 | * FakeItEasy
137 | * Assertion
138 | * FluentAssertion
139 | * Shouldly
140 | * Integration Testing
141 | * WebApplicationFactory
142 | * TestServer
143 | * Behavior Testing
144 | * SpecFlow
145 | * BDDfy
146 | * LightBDD
147 | * E2E Testing
148 | * Selenium
149 | * Puppeteer-Sharp
150 |
151 | ### Microsserviços
152 | * Message-Broker
153 | * RabbitMQ
154 | * Apache Kafka
155 | * ActiveMQ
156 | * Azure Service Bus
157 | * NetMQ
158 | * Message-Bus
159 | * MassTransit
160 | * NServiceBus
161 | * EasyNetQ
162 | * CAP
163 | * API Gateway
164 | * Ocelot
165 | * Containerization
166 | * Docker
167 | * Orcherstration
168 | * Kubernetes
169 | * Docker Swarm
170 | * Reverse Proxy
171 | * YARP
172 | * Other
173 | * Orleans
174 | * Steeltoe
175 | * Dapr
176 | * Tye
177 |
178 | ### CI/CD
179 | * Github Actions
180 | * Azure Pipelines
181 | * Travis CI
182 | * Jenkins
183 | * Circle CI
184 | * TeamCity
185 |
186 | ### Design Patterns
187 | * CQRS
188 | * Decorator
189 | * Strategy
190 | * Builder
191 | * Singleton
192 | * Facade
193 |
194 | ### Client-Side Libraries
195 | * Blazor
196 |
197 | ### Template Engine
198 | * Razor
199 | * DotLiquid
200 | * Scriban
201 | * Fluid
202 |
203 | ### GTK libs
204 | * MediatR
205 | * Fluent Validation
206 | * Polly
207 | * Benchmark.NET
208 | * NodaTime
209 | * GenFu
210 | * Swashbuckle
211 |
212 | ## Minha versão
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 📮Blog
2 | Este repositório é destinado à artigos de alunos do balta.io, veja como você pode contribuir abaixo.
3 |
4 | ## 🟣 Como funciona o Blog
5 | O nosso [Blog](https://balta.io/blog) tem como principal conteúdo os artigos técnicos produzidos pelo próprio [André Baltieri](https://github.com/andrebaltieri), pessoas da [equipe balta.io](https://github.com/orgs/balta-io/people) e alunos da plataforma.
6 |
7 | ## 🟣 Submetendo uma proposta de artigo
8 | Sabendo qual o tema que pretende abordar, chegou a hora de apresentar a sua proposta. Para isto você deve preencher os dados do template [aqui!](https://github.com/balta-io/blog/issues/new?assignees=BrewertonSantos&labels=proposta&template=submiss-o-de-artigo.md&title=Proposta+de+artigo%3A++TITULO+DO+ARTIGO+AQUI). É importante ler corretamente e preencher as informações conforme esperado.
9 |
10 | Frequêntemente nos deparamos com propostas onde o título do issue ainda está "TíTULO DO ARTIGO AQUI" como no template, isto passa uma primeira impressão de que o autor não está dando a atenção correta ao que está fazendo e consequêntemente a credibilidade é afetada. Entenda melhor é esperado na submissão da sua proposta:
11 |
12 | ### 🗞️ Tema do artigo
13 | Antes de escrever é importante alinharmos um tema. Os temas que mais fazem sentido para as tecnologias que trabalhamos serão mais aceitos. VocÊ pode escrever sobre ferramentas, metodologisa, arquitetura, bibliotecas, frameworks e etc.
14 |
15 | Então no tema do artigo você deve inserir um título que considere eficaz e direto quanto ao conteúdo que deseja escrever.
16 |
17 | ### 📰 Sobre o que você pretende escrever
18 | Neste tópico o objetivo é que resuma seu objetivo para o artigo envolvendo o assunto que será abordado, os processos que utilizadá, suas referências, onde pretende chegar e qual a finalidade do artigo.
19 |
20 | ### Previsão para submissão de artigo
21 | A data de submissão do artigo se refere à data em que você concluirá o desenvolvimento do artigo. Como se trata de uma previsão, esperamos que uma data seja determinada mas obviamente caso aconteça algo durante o processo você pode retificar esta data. No caso de retificação esperamos que nos notifique para que possamos trabalhar na agenda de conteúdo sem surpresas.
22 |
23 | ## 🟣 O que é esperado de um artigo técnico para nosso blog?
24 | Os artigos devem estar organizados por tópicos e parágrafos corretamente. Os trechos de código devem estar inseridos dentro das marcações de código referênciando a linguagem corretamente para exibir o highlight. Exemplo:
25 |
26 | Código C# (CSharp):
27 |
28 | ```csharp
29 | Console.WriteLine("Hello World!");
30 | ```
31 |
32 | ### Conteúdo
33 | Após o tema ter sido aceito, você pode começar a escrever seu artigo, ele tem que ser no formato **Markdown** e conter pelo menos **1000 palavras**. Lembre-se de adicionar sumário e tópicos corretamente em seu artigo.
34 |
35 | `NOTA 1`: Caso tenha usado outros artigos, documentação e pesquisas durante o processo de desenvolvimento do seu artigo. Adicione as referências no final do seu artigo.
36 |
37 | `NOTA 2`: Caso ainda tenha dúvidas e/ou um exemplo aplicado te auxilie melhor a entender, utilize [este artigo](https://github.com/balta-io/blog/blob/main/linguagens-de-programacao/index.md) como exemplo. Ele contém sumário, tópicos organizados, parágrafos, imagens e referências.
38 |
39 | ### Imagens
40 | Utilize imagens grandes e visíveis, e não se esqueça de salvá-las dentro de uma pasta `imagens` no mesmo diretório do seu artigo, vamos precisar dos arquivos destas imagens para colocar seu artigo no ar.
41 |
42 | ### 🟣 Publicação
43 | Para publicar seu artigo será necessário fazer um fork do nosso blog clicando no botão fork localizado no canto superior direito da tela abaixo do ícone de usuário do seu GitHub:
44 |
45 | 
46 |
47 | Depois basta imcorporar seu artigo ao fork criado no seu perfil e fazer um **Pull request** para este repositório, lembrece de seguir os passos: Criar uma pasta (Não usar espaços ou caracteres especiais no nome da pasta) com os seguintes arquivos:
48 | * nome-do-artigo/index.md -> Seu artigo
49 | * nome-do-artigo/images/ -> Imagens do seu artigo
50 |
51 | Nós vamos priorizar artigos escritos **exclusivamente** para nossa plataforma.
52 |
--------------------------------------------------------------------------------
/removendo-codigo-desnecessario-dotnet/index.md:
--------------------------------------------------------------------------------
1 | Neste artigo vamos conferir os recursos do C#/.NET que nos permite desabilitar ou omitir parte código em produção.
2 |
3 | ## Quen nunca...
4 | Quem nunca esqueceu um `Console.WriteLine` no código e enviou tudo para produção? Pois é, isto é uma prática comum que fazemos mas que pode ter consequências maiores.
5 |
6 | Já vi casos onde havia `Console.WriteLine(ConnectionString)`, imprimindo usuário e senha de acesso ao banco de dados. Ruim, não é?
7 |
8 | ### Debug.WriteLine
9 | Uma abordagem bem mais sutil que você pode começar a adotar é o `Debug.WriteLine`, desta forma, a não ser que seu código seja compilado como `DEBUG`, você não terá acesso a esta linha em produção.
10 |
11 | Tudo contido no `Debug` só será realizado no modo **Debug**, previnindo automaticamente qualquer exposição de informações em produção.
12 |
13 | ### A melhor maneira
14 | Não printar este tipo de informação! Esta é a melhor maneira de previnir qualquer tipo de vazamento de informação da sua aplicação.
15 |
16 | Se você precisa obter uma configuração específica ou inspecionar algum valor em produção, utilize o **Remote Debugger** para isto, mas evite deixar logs desnecessários.
17 |
18 | ## Conditional Debug
19 | Além do `Debug.WriteLine` e todos outros métodos contidos no `Debug`, podemos decorar nossos métodos com o atributo `Conditional` e especificar que o mesmo só estará disponível durante o modo **DEBUG**.
20 |
21 | ```csharp
22 | [System.Diagnostics.Conditional("DEBUG")]
23 | public void MeuMetodo(string parametro)
24 | { ... }
25 | ```
26 |
27 | Este trecho de código só poderá ser invocado durante o modo **DEBUG**, inclusive a própria IDE te alertará sobre isto, colocando um destaque/warning sempre que fizer uso de um método como este.
28 |
29 | O `ConditionalAttribute` trabalha com símbolos do compilador e podemos criar várias condições que atendam este símbolos, como mostrado abaixo.
30 |
31 | ```csharp
32 | #define CONDITION1
33 | #define CONDITION2
34 |
35 | using System;
36 | ...
37 | ```
38 | Com as condições definidas, podemos utilizar o `ConditionalAttribute` para indicar ao compiladore que uma chamada de método ou atributo deve ser ignorado, a menos que um símbolo de compilação condicional especificado seja definido.
39 |
40 | ```csharp
41 | [Conditional("CONDITION1")]
42 | public static void Method1(int x)
43 | {
44 | Console.WriteLine("CONDITION1 is defined");
45 | }
46 |
47 | [Conditional("CONDITION1"), Conditional("CONDITION2")]
48 | public static void Method2()
49 | {
50 | Console.WriteLine("CONDITION1 or CONDITION2 is defined");
51 | }
52 | ```
53 | Como resultado neste caso, teríamos os métodos disponíveis apenas se as condições fossem verdadeiras.
54 |
55 | Da mesma forma, podemos utilizar o `#undef CONDITIONAL1` para remover esta condição e compilar a aplicação sem os métodos informados, já que as condições não atendem mais.
56 |
57 | ## IF
58 | Além do atributo `Conditional` temos a possibilidade de utilizar `IF`, para atender trechos maiores de código por exemplo.
59 |
60 | ```csharp
61 | public void Method2()
62 | {
63 | #if CONDITION1
64 | ...
65 | #endif
66 | }
67 | ```
68 |
69 | Um dos cenários mais comuns é usar a condicional `DEBUG`, contina no próprio ambiente do .NET para esta tomada de decisão.
70 |
71 | ```csharp
72 | #if DEBUG
73 | public void MeuMetodo(string parametro)
74 | { ... }
75 | #endif
76 | ```
77 |
78 | ## O que vai para produção?
79 | Mas se ambos teoricamente fazem a mesma coisa, qual a real diferença? Quando utilizar um ou outro. Bem, na verdade existe uma grande diferença.
80 |
81 | No caso do `#if DEBUG` o código nem chegará ao IL, ele simplesmente será eliminado antes, como se não existisse.
82 |
83 | No caso do `Conditional Attribute` o código chegará no IL mas será omitido a menos que a condição seja satisfatória.
84 |
85 | Em resumo, se você quer de fato **descartar** este código durante a compilação, o `#if DEBUG` é a melhor opção, vai economizar alguns bytes.
86 |
87 | Porém, se você precisa deste código na compilação final da sua aplicação, se eventualmente necessitará trocar do modo **RELEASE** para **DEBUG** para qualquer tipo de testes, o `Conditional Attribute` é a melhor opção.
88 |
89 |
90 | ## Fonte
91 | * https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.conditionalattribute?redirectedfrom=MSDN&view=net-6.0
--------------------------------------------------------------------------------
/aspnet-qrcode/index.md:
--------------------------------------------------------------------------------
1 | Neste artigo vamos aprender a gerar um QRCode via ASP.NET Core de forma simples e rápida.
2 |
3 | ## Versão em vídeo
4 |
5 |
6 |
7 |
8 | ## QRCoder
9 |
10 | Para facilitar nosso trabalho, vamos utilizar um pacote chamado **QRCoder**, um projeto Open Source disponível no GitHub e via Nuget.
11 |
12 |
13 | ```
14 | dotnet new mvc -o MeuApp
15 | cd MeuApp
16 | dotnet add package QRCoder
17 | ```
18 |
19 | Pronto, temos nosso projeto criado com o pacote necessário para começarmos.
20 |
21 | ## Organizando o projeto
22 |
23 | A ideia aqui é criar uma classe que vai permitir o reuso do QRCode em diferentes pontos do nosso App.
24 |
25 | O pacote em sí já faz muita coisa, mas parte de gerar imagens, particulamente prefiro separar para um reuso ainda maior.
26 |
27 | ### Gerando o QRCode
28 |
29 | O trecho para gerar um QRCode utilizando o **QRCoder** é bem simples, precisamos do QRCodeGenerator e dos dados do QRCode.
30 |
31 | ```csharp
32 | var qrGenerator = new QRCodeGenerator();
33 | var qrCodeData = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
34 | var qrCode = new QRCode(qrCodeData);
35 | var qrCodeImage = qrCode.GetGraphic(10);
36 | return qrCodeImage;
37 | ```
38 |
39 | Para ficar ainda melhor, vamos separar este código em um método que já retorna um Bitmap. Isto vai nos ajudar em todo processo.
40 |
41 | ```csharp
42 | public static Bitmap GenerateImage(string url)
43 | {
44 | var qrGenerator = new QRCodeGenerator();
45 | var qrCodeData = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
46 | var qrCode = new QRCode(qrCodeData);
47 | var qrCodeImage = qrCode.GetGraphic(10);
48 | return qrCodeImage;
49 | }
50 | ```
51 |
52 | Em alguns pontos também precisei dos bytes da imagem ao invés do Bitmap, então decidi criar dois métodos adicionais, um para retornar os bytes da imagem e outro para retornar os bytes dado uma URL.
53 |
54 | ```csharp
55 | public static byte[] GenerateByteArray(string url)
56 | {
57 | var image = GenerateImage(url);
58 | return ImageToByte(image);
59 | }
60 |
61 | private static byte[] ImageToByte(Image img)
62 | {
63 | using var stream = new MemoryStream();
64 | img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
65 | return stream.ToArray();
66 | }
67 | ```
68 |
69 | Como resultado final, nossa classe ficou com os seguintes métodos.
70 |
71 | ```csharp
72 | public static class QrCodeGenerator
73 | {
74 | public static Bitmap GenerateImage(string url)
75 | {
76 | var qrGenerator = new QRCodeGenerator();
77 | var qrCodeData = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
78 | var qrCode = new QRCode(qrCodeData);
79 | var qrCodeImage = qrCode.GetGraphic(10);
80 | return qrCodeImage;
81 | }
82 |
83 | public static byte[] GenerateByteArray(string url)
84 | {
85 | var image = GenerateImage(url);
86 | return ImageToByte(image);
87 | }
88 |
89 | private static byte[] ImageToByte(Image img)
90 | {
91 | using var stream = new MemoryStream();
92 | img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
93 | return stream.ToArray();
94 | }
95 | }
96 | ```
97 |
98 | ## Utilizando o QRCode
99 |
100 | Agora tudo que temos a fazer é chamar nosso gerador em algum método do controlador.
101 |
102 | ```csharp
103 | var image = QrCodeGenerator.GenerateByteArray("https://balta.io");
104 | ```
105 |
106 | Com a imagem gerada, podemos responder com um FileResult passando os bytes da imagem e o Mime/Type.
107 |
108 | ```csharp
109 | [HttpGet("qrcode")]
110 | public IActionResult GetQrCode()
111 | {
112 | var image = QrCodeGenerator.GenerateByteArray("https://balta.io");
113 | return File(image, "image/jpeg");
114 | }
115 | ```
116 |
117 | Desta forma, ao executar nossa aplicação, teremos o **QRCode** sendo exibido na URL abaixo.
118 |
119 | ```
120 | https://localhost:5001/qrcode
121 | ```
122 |
123 | ### Utilizando no HTML
124 |
125 | Para renderizar o QRCode na tela, basta utilizar a tag img com a URL anterior.
126 |
127 | ```html
128 |
129 | ```
130 |
131 | Pronto! Temos um gerador de QRCode com ASP.NET.
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/e-viavel-programar-em-csharp-no-linux-em-2022/index.md:
--------------------------------------------------------------------------------
1 | ## Introdução
2 |
3 | C# e Linux, um casamento complicado? A um bom tempo atrás, era apenas possível desenvolver, sem dor de cabeça, para o ambiente .Net somente no Windows, com algumas ressalvas com a “falecida” IDE MonoDevelop (https://www.monodevelop.com/) para ajudar o pinguim.
4 |
5 | Bom, um pouco de história: em 2016, a Microsoft anunciava o .Net Core, uma reimplementação do famoso e amado, por uns odiados, Framework de sua autoria, dessa vez disponível para, além do Windows, o macOS e Linux. Claro, nem tudo são flores e é impossível fazer uma reimplementação de um gigantesco Framework igualmente completo como o seu “pai” do dia para a noite e distribuir por ai aos SO’s de maior relevância do mercado, mesmo que de forma gratuita e open source.
6 |
7 | No ano de 2020, a versão 5 do .Net foi disponibilizada como estável, tanto SDK como para run time, o que marcou a unificação de uma baita confusão de versões do .Net, deixando para trás o .Net Framework (aquele exclusivo para Windows), .Net Core (versões iniciais do .Net open source) e a criação do padrão “.Net Standard.” Mas, agora retomando o rumo da venta. É viável programar em C# no Linux em 2022? Bom, a resposta é dupla: sim e não.
8 |
9 | ## Explicando
10 |
11 | **Por que sim?**
12 |
13 | Com o amadurecimento da ferramenta ao passar dos anos e, um gigante apoio, da JetBrains com a IDE Rider, desenvolver com C#, especialmente para a Web, Console applications, Worker Services e Unit Tests, hoje possuímos uma baita ferramenta completa, apesar de salgada, para desenvolver com comodidade no Linux (até mesmo no Mac, além do Visual Studio for Mac, e no Windows, caso não queira o Visual Studio). Para os que ainda duvidam, deem uma olhada no meu mais recente e maduro projeto de ASP Net Core feito 100% no Linux: [A basic Snack Store MVC project.](https://github.com/JGMelon22/Snacks_Web_MVC_SqlServer)
14 |
15 | 
16 |
17 | **Por que não?**
18 |
19 | Alguns podem estranhar que eu não comentei sobre o editor de textos, muito confundido com IDE, Visual Studio Code. O Visual Studio Code, apesar de ficar bem redondinho para codificar em C# com algumas extensões, especialmente as da imagem a baixo, acaba pecando por ser limitado em alguns aspectos, sendo os mais chatinho a falta de facilidade para auxiliar a geração de itens do Scaffolding ASP .NET Core - Usando os recursos do Scaffolding, a necessidade de usar a implementação “curada” da Microsoft do Visual Studio Code (o que complica aos que usam distros como o Solus, pois a versão disponível nos repositório é a VSCode-oss) (GitHub - microsoft/vscode: Visual Studio Code) e a falta, por hora, de uma alternativa ao WinForms, caso você queira desenvolver para computadores locais, mas não curte nem um pouco se aventurar na web com um tico de JavaScript, CSS, Html e Bootstrap.
20 |
21 | 
22 |
23 | 
24 |
25 | ## Fazendo uma breve tangência:
26 |
27 | há esperança de um dia surgir uma alternativa ao WinForms, para Mac (e talvez Linux)? Sim, jovem Padawan e esse sonho pode estar cada vez mais perto devido ao MAUI, um acrônimo para Multi-platform App UI, que além de possibilitar reusar o mesmo código para desktop, permitirá portar o programa em questão para mobile (IOS e Android), aposentando o legado Xamarin Forms. A notícia triste é que o MAIU foi adiado para Q2 de 2022 (.NET MAUI: Preview 8 Available, But GA Postponed to Q2 2022).
28 |
29 | Mas existem boas alternativas já disponíveis como o [AvaloniaUI](https://avaloniaui.net/) e o [UNO Plataform](https://platform.uno/), ambos visando o desenvolvimento multiplataforma, mas com um toque de XAML (na unha).
30 |
31 | ## Conclusão
32 |
33 | Bom, caso você opte pelo desenvolvimento web, ASP Net, desenvolver em C# no Linux, até o presente o momento, será uma experiência bastante agradável. Mas, caso você precise desenvolver aplicações locais usando WinForms, eu sinto em informar que somente pelo Windows mesmo, visto que o WinForms, assim como o Visual Basic For Application, depende de componentes do Windows para funcionar [Design Windows Forms | JetBrains Rider](https://www.jetbrains.com/help/rider/Working_with_Windows_Forms.html), você precisará usar o SO da Microsoft (ou via máquina virtual ou dual boot).
34 |
35 | ## Continue lendo:
36 |
37 | [Visual Studio Code - Instalação e costumização](https://balta.io/blog/visual-studio-code-instalacao-customizacao)
38 |
39 | [WSL - Windows Subsystem for Linux](https://balta.io/blog/wsl)
40 |
41 | [Plataform Specific no .NET](https://balta.io/blog/dotnet-platform-specific)
42 |
--------------------------------------------------------------------------------
/csharp-parse-tryparse/index.md:
--------------------------------------------------------------------------------
1 | Parse e TryParse são dois métodos que temos para converter, ou tentar converter, uma string para outro de forma explícita no C#.
2 |
3 | ## Parse e TryParse
4 | Os métodos `Parse` e `TryParse` nos permitem converter ou tentar converter uma `string` para um outro tipo. No caso, todos os tipos **built-in** do .NET possuem estes métodos.
5 |
6 | ## Utilizando o Parse
7 | O `Parse` funciona como uma extensão aos métodos **built-in**, onde podemos invocar o método informando uma `string`, como por exemplo `int.Parse("123")`.
8 |
9 | Abaixo podemos ver três exemplos de conversões de `string` para outros tipos **built-in** utilizando `Parse`, incluindo um `DateTime` que é uma estrutura, um tipo mais complexo.
10 |
11 | ```csharp
12 | var valor = int.Parse("123");
13 | var valor2 = bool.Parse("true");
14 | var valor3 = DateTime.Parse("01/01/2022");
15 |
16 | Console.WriteLine(valor);
17 | Console.WriteLine(valor2);
18 | Console.WriteLine(valor3);
19 | ```
20 | Como resultado da execução deste programa temos o seguinte texto sendo impresso na tela.
21 |
22 | ```
23 | 123
24 | True
25 | 1/1/2022 12:00:00 AM
26 | ```
27 |
28 | ## IFormatProvider
29 | Continuando o exemplo anterior, temos um `DateTime` e estamos passando o valor `01/01/2022` para o mesmo. Este valor foi proposital para não causar nenhum erro.
30 |
31 | Agora vamos considerar uma nova data, `28/10/2021`, onde temos o formato `dd/MM/yyyy`, um formato utilizado aqui no Brasil, mas diferente dos EUA (Formato padrão do .NET) que utiliza `MM/dd/yyyy`.
32 |
33 | ```
34 | Unhandled exception. System.FormatException: String '28/10/2021' was not recognized as a valid DateTime.
35 | at System.DateTime.Parse(String s)
36 | at Program.$(String[] args) in C:\dev\CsharpTryParse\Program.cs:line 8
37 | ```
38 |
39 | Neste caso, a conversão falharia, pois `28/10/2021` não é uma data válida nos EUA, o correto seria `10/28/2021`, mas felizmente conseguimos contornar isto utilizando uma cultura.
40 |
41 | ```csharp
42 | var culture = new CultureInfo("pt-BR");
43 | var valor3 = DateTime.Parse("28/10/2021", culture);
44 | ```
45 | Note que agora temos um objeto do tipo `CultureInfo`, que define a cultura como `pt-BR` (Português do Brasil) e quando executamos o `Parse`, informamos também a cultura, resultando no sucesso da conversão.
46 |
47 | ### NumberStyles
48 | Outro modificador que podemos utilizar (Existem vários) é o `NumberStyles`, que nos permite trabalhar nas pontuações dos números no caso de inteiros.
49 |
50 |
51 | ```csharp
52 | Console.WriteLine(int.Parse("1234", NumberStyles.None));
53 | // 1234
54 |
55 | Console.WriteLine(int.Parse("12123.0", NumberStyles.AllowDecimalPoint));
56 | // 12123
57 |
58 | Console.WriteLine(int.Parse("123,456", NumberStyles.AllowThousands));
59 | // 12356
60 | ```
61 | Ainda podemos adicionar a cultura aos números, junto aos `NumberStyles` para trabalhar na relação "ponto ou vírgula` dos valores.
62 |
63 | ## TryParse
64 | Como pudemos notar nos exemplos anteriores, ao usar o `Parse` temos uma tentativa de conversão de uma `string` para outro tipo, o que nem sempre ocorrerá com sucesso.
65 |
66 | No caso demonstrado com o `DateTime` mesmo, tivemos um `FormatException` pois não informamos a data no formato correto.
67 |
68 | ```
69 | Unhandled exception. System.FormatException: String '28/10/2021' was not recognized as a valid DateTime.
70 | at System.DateTime.Parse(String s)
71 | at Program.$(String[] args) in C:\dev\CsharpTryParse\Program.cs:line 8
72 | ```
73 |
74 | Para evitar este tipo de situação, temos o `TryParse` que resulta em um booleano informando se a conversão foi possível e caso verdade, o valor da conversão.
75 |
76 | ```csharp
77 | var deuCerto = int.TryParse("45689", out var valor);
78 |
79 | Console.WriteLine(deuCerto);
80 | Console.WriteLine(valor);
81 | ```
82 |
83 | Note que o `TryParse` faz uso do `out var valor`, então o resultado direto da execução dele é um `bool` e não o valor convertido em sí. Este valor pode ser extraído da variável definida no `out`.
84 |
85 | Como resultado de uma conversão de sucesso, temos o seguinte texto sendo impresso no terminal.
86 |
87 | ```
88 | True
89 | 45689
90 | ```
91 |
92 | Agora vamos ao segundo cenário, onde o `TryParse` mais se destaca. Aqui temos uma tentativa de conversão que vai falhar, afinal estamos tentando converter `"asdaasd"` para um `int`.
93 |
94 | ```csharp
95 | var deuCerto = int.TryParse("asdaasd", out var valor);
96 |
97 | Console.WriteLine(deuCerto);
98 | Console.WriteLine(valor);
99 | ```
100 |
101 | Neste caso, não teremos uma exceção e sim os valores `false` para o resultado da execução e `0` para o `int`. Isto ocorre pois o `int` é um tipo de valor e seu valor inicial é sempre 0.
102 |
103 | ```
104 | False
105 | 0
106 | ```
107 |
108 | ## Conclusão
109 | Fazer conversões de valores no C# é uma tarefa fácil e temos vários recursos para isto, incluindo o Parse e TryParse como vimos neste artigo.
110 |
--------------------------------------------------------------------------------
/fundamentos-testes-de-unidade/index.md:
--------------------------------------------------------------------------------
1 | Ter uma base sólida em testes de unidade é fundamental para que você possa se mover por diversas tecnologias e linguagens, e neste artigo, vou colocar os principais fundamentos que você precisa para ser fera em testes.
2 |
3 | Código Testável
4 | ---------------
5 |
6 | Seja programação orientada à objetos ou programação funcional, escrever um bom código é a base para execução de testes com facilidade.
7 |
8 | O uso de SOLID/Clean Code na OOP ou Pure Functions/outras boas práticas com JS é indispensável para criarmos um ambiente propício a testes.
9 |
10 | Bons códigos são testados mais facilmente, tomam menos tempo, dão menos trabalho, logo são muito mais simples de serem executados.
11 |
12 | Se você quer chegar a uma ótima cobertura de testes, passe primeiro pela base da linguagem que você utiliza, por padrões, boas práticas e um código limpo.
13 |
14 | Saiba o que testar
15 | ------------------
16 |
17 | Se você tentar testar tudo em sua aplicação, talvez você desanime e abandone os testes. Eu digo isto porque eventualmente vejo testes sobre entidades anêmicas ou validações simples como se um nome aceita X caracteres.
18 |
19 | Para intuito de aprendizado eu acho excelente, quanto mais exercitar os testes, melhor. Mas se não está sobrando tempo, foque em testar o que realmente importa, como os cálculos da aplicação, validações de fluxos mais complexos e por aí vai.
20 |
21 | Se sobrar tempo, testa o resto! Quanto mais testes, mais coberto você está, mas saber de fato o que precisa ser testado é importante.
22 |
23 | Embora essa seja uma decisão mais de negócio, é quase que intuitivo que nossos testes sejam sobre as entidades do nosso domínio, afinal, as regras ficam lá.
24 |
25 | Apenas atente-se para não trazer entidade irrelevantes, que poderiam ser apenas CRUD para seu domínio.
26 |
27 | Compartilhamento e Reuso de Código
28 | ----------------------------------
29 |
30 | Quantas vezes você testou se um E-mail era válido? Se um CPF era válido? Pois é!
31 |
32 | No .NET temos o NuGet e no JS o NPM, que são ótimos gerenciadores de pacote e você pode ter um para sua empresa, privado.
33 |
34 | Sempre que falamos em Primitive Obsession e Value Objects, falamos em compartilhar exatamente este tipo de código. Quantos VOs de E-mail, CPF e afins você já criou, e quantos você compartilhou?
35 |
36 | Compartilhamento e reuso de código afetam diretamente os testes de unidade. Quanto mais você reusa, menos testes necessita.
37 |
38 | Sigo este princípio com o Flunt, onde temos um pacote de validações já testadas. Desta forma, não precisamos executar os testes simples, pois já são garantidos pelo framework.
39 |
40 | O mesmo acontece com EF/NHibernate. Não testamos seus Contexts ou nada deles, pois eles já garantem que isto está funcionando.
41 |
42 | Pense desta forma, crie, teste, distribua, e seus testes cairão pela metade!
43 |
44 | Red, Green, Refactor
45 | --------------------
46 |
47 | Sabendo o que temos que testar, escreva todos os testes e faça os falhar. Você vai perceber que enquanto escreve o título dos testes, virão novas ideias, novos testes a serem escritos.
48 |
49 | Com uma certa frequência, enquanto estou desenvolvendo o domínio, me vem alguns testes na cabeça, e sempre anoto eles nos testes de unidade.
50 |
51 | Minha recomendação é que sempre que lembrar de algo que precisa ser testado, vá até os testes daquela entidade, anote o título do teste e faça-o falhar.
52 |
53 | Ao término da escrita do domínio e dos testes, você terá uma gama de testes, todos vermelhos, e a ideia do próximo passo, é fazê-los passarem com o mínimo de esforço possível.
54 |
55 | Deixe tudo verde, tudo passando, e vai notar que há uma certa bagunça em seu código. Isto deve-se ao fato que escrever testes também requer uma estruturação do código.
56 |
57 | Se simplesmente deixarmos o código acumular, uma hora pagaremos por isto, pois tal bagunça pode influenciar nos testes.
58 |
59 | Passamos então para o Refactor, onde vamos refatorar os testes, de forma a reutilizar a massa de dados em diversos testes de unidade, criar repositórios falsos e por aí vai.
60 |
61 | Esta é uma das técnicas que mais gosto na escrita de testes de unidade. Ela nos dá uma visão do que precisamos testar e a obrigação de criar testes bem escritos.
62 |
63 | Cultura de Testes
64 | -----------------
65 |
66 | Já comentei sobre cultura de testes em artigos aqui no balta.io e reforço a importância dela aqui.
67 |
68 | Ter uma visão única da importância dos testes, como um todo na empresa, é fundamental para ter códigos testáveis.
69 | Sinceramente, não adianta a equipe ter os melhores Devs, escrever os melhores testes, se na hora que o prazo aperta, os testes são deixados de lado. A cultura vem para evitar isto.
70 |
71 | Resumo
72 | ------
73 |
74 | Escreva códigos testáveis, saiba bem o que testar, reuse e distribua seu código testado para otimizar seus testes de unidade.
75 |
76 | Utilize técnicas como o Red, Green, Refactor e principalmente semeie a cultura de testes na sua empresa.
--------------------------------------------------------------------------------
/aspnet-serilog/index.md:
--------------------------------------------------------------------------------
1 | Neste artigo vamos aprender como podemos utilizar o pacote Serilog para logar informações das nossas aplicações.
2 |
3 | ## O que é o Serilog?
4 | O **Serilog** é uma biblioteca para log de informações de qualquer aplicação .NET, que trabalha com **Sinks** como base.
5 |
6 | O **Serilog** em sí, é uma estrutura que nos permite salvar quaisquer tipos de informação, de forma organizada, durante a execução da aplicação.
7 |
8 | ### Sinks
9 | Quando trabalhamos com logs, os gostos e necessidades variam muito. Cada empresa ou time, opta por concentrar seus logs em um local diferente e o **Serilog** auxilia nisso.
10 |
11 | O que acontece é que o Serilog possui apenas a implementação básica dos logs e os **Sinks** fazem todo o trabalho sujo aqui.
12 |
13 | Desta forma, caso queira que o **Serilog** escreva seus logs em um arquivo, basta utilizar o **Sink.File**. O mesmo acontece para E-mails com **Sink.Email** e até para o Discord com **Sink.Discord**.
14 |
15 | Você também pode criar seu próprio **Sink** caso queira armazenar os logs em algum local específico da sua empresa cujo os Sinks padrões não te atenda.
16 |
17 | ## Setup
18 | O primeiro passo para utilizar o **Serilog** é fazer a instalação do seu pacote principal, cujo todos os Sinks derivarão. Isto pode ser feito executando o comando abaixo.
19 |
20 | ```
21 | dotnet add package Serilog.AspNetCore
22 | ```
23 | Para finalizar, precisamos adicionar o `UseSerilog` no `Host` da aplicação, conforme mostrado abaixo.
24 |
25 | ```csharp
26 | builder.Host.UseSerilog(...);
27 | ```
28 |
29 | É importante notar, que neste caso deixamos as configurações vazias por enquanto (`...`), o que causará um erro se tentarmos executar o programa.
30 |
31 | Posteriormente veremos como configurar os **Sinks** da maneira correta, para diferentes tipos de log.
32 |
33 | ### Log no Console
34 | A primeira forma e mais simples de termos quaisquer informações durante a execução das nossas aplicações é visualizar o **Console** (Terminal onde a aplicação está sendo executada).
35 |
36 | Para logar as informações no **Console** utilizando **Serilog**, precisamos primeiro configurar o método `WriteTo`, apontando para `Console`.
37 |
38 | ```csharp
39 | builder.Host.UseSerilog((ctx, lc) => lc
40 | .WriteTo.Console(LogEventLevel.Debug)
41 | ```
42 |
43 | Note que neste exemplo utilizamos o `LogEventLevel.Debug` o que significa que **apenas mensagens de Debug** serão logadas no **Console**.
44 |
45 | Neste ponto, todas as mensagens de **Debug**, incluindo as do próprio .NET, serão logadas. O mesmo vale para **Warnings** e **Errors**, é só mudar o `LogEventLevel` para tê-las logadas.
46 |
47 | #### Mensagens customizadas
48 | Caso queira disparar alguma mensagem customizada durante a execução da aplicação, podemos utilizar o `Log` do namespace `Serilog`, informando o tipo da mensagem e texto que desejamos logar.
49 |
50 | ```csharp
51 | using Serilog;
52 |
53 | Log.Error("Mensagem de erro");
54 | Log.Information("Mensagem de informação");
55 | Log.Fatal("Erro fatal");
56 | Log.Debug("Mensagem de Debug");
57 | Log.Warning("Mensagem de Warning");
58 | ```
59 |
60 | ### Log no E-mail
61 | Seguindo a mesma linha de raciocínio anterior, podemos ter as mensagens logadas via E-mail. Neste caso temos que ter um cuidado especial para não encher a caixa de E-mails de mensagens.
62 |
63 | O **Serilog** possui um **Sink** que faz este trabalho, e podemos instalá-lo através do pacote como demonstrado abaixo.
64 | ```
65 | dotnet add package Serilog.Sinks.Email
66 | ```
67 |
68 | Feito isto, tudo que precisamos fazer é configurar o **Sink** no `Program.cs` como fizemos anteriormente com o **Console**.
69 |
70 | ```csharp
71 | builder.Host.UseSerilog((ctx, lc) => lc
72 | .WriteTo.Console(LogEventLevel.Debug)
73 | .WriteTo.Email(new EmailConnectionInfo
74 | {
75 | Port = 587,
76 | EmailSubject = "TESTE",
77 | EnableSsl = true,
78 | FromEmail = "hello@balta.io",
79 | MailServer = "smtp.sendgrid.net",
80 | NetworkCredentials = new NetworkCredential("apikey", "pwd"),
81 | ToEmail = "hello@balta.io",
82 | IsBodyHtml = true
83 | }));
84 | ```
85 |
86 | ### Log no arquivo
87 |
88 | Por fim temos o `Serilog.Sinks.File` que nos permite logar mensagens em um arquivo (Texto neste caso). Este método particularmente é um dos que mais utilizo.
89 |
90 | ```csharp
91 | builder.Host.UseSerilog((ctx, lc) => lc
92 | .WriteTo.Console(LogEventLevel.Debug)
93 | .WriteTo.File("log.txt",
94 | LogEventLevel.Warning,
95 | rollingInterval: RollingInterval.Day));
96 | ```
97 |
98 | ## Outros Sinks
99 |
100 | Algo que gosto no **Serilog** é o ótimo suporte por parte da comunidade. É quase impossível precisar de um **Sink** que ainda não existe, [**confira a lista completa aqui**](https://github.com/serilog/serilog/wiki/Provided-Sinks).
101 |
102 | Aqui no balta por exemplo, utilizamos o **Sink** do **Discord**, já que temos nossas informações todas concentradas lá. É muito legal conseguir ver o que está acontecendo no site e ainda poder agir de forma pro-ativa.
103 |
104 | ## Conclusão
105 | Escrever logs de forma simples e fácil, com extesões e suporte para múltiplos formatos e plataformas no .NET é com o **Serilog**. Ele é um dos meus pacotes preferidos!
--------------------------------------------------------------------------------
/dotnetconf-dotnetcore-resumo/index.md:
--------------------------------------------------------------------------------
1 | No dia 25 de setembro tivemos o evento oficial de lançamento do .NET Core 3.0 e neste artigo eu vou resumir as novidades e deixar alguns vídeos, dos lançamentos e de uma live que fizemos sobre o assunto.
2 |
3 | Suporte ao C# 8.0
4 | -----------------
5 |
6 | O C# é uma das minhas linguagens favoritas, e com certeza uma das melhores e mais completas do mercado. Embora a linguagem já esteja bem madura, sempre estão vindo novidades boas, e ela chegou à versão 8.0, com seu suporte pelo .NET Core 3.0.
7 |
8 | .NET Standard 2.1
9 | -----------------
10 |
11 | Com a chegada do .NET Core 3.0 também veio o .NET Standard 2.1, uma Surface API para padronizar os projetos. Para usar o .NET Standard 2.1 basta setar o netstandard2.1 no Target Framework do seu arquivo de configuração.
12 | Quer saber o que cada versão do .NET Standar suporta? Então consulte este link: [https://docs.microsoft.com/pt-br/dotnet/standard/net-standard](https://docs.microsoft.com/pt-br/dotnet/standard/net-standard).
13 |
14 | EXE único
15 | ---------
16 |
17 | Agora Podemos adicionar as tags true ao arquivo de configuração ou utilizar o comando dotnet publish -r win10-x64 /p:PublishSingleFile=true para que os executáveis sejam gerados em um único arquivo. Chega de pastas e vários arquivos para suas Apps, agora pode ficar tudo em um só.
18 |
19 | Melhorias no tamando dos Assemblies
20 | -----------------------------------
21 |
22 | Agora temos uma tag chamada PublishTrimmed que ao adicionada ao arquivo de configuração do projeto, analisa o IL e remove os Assemblies não utilizados.
23 |
24 | ReadyToRun
25 | ----------
26 |
27 | Agora podemos melhorar o tempo de inicialização dos Apps .NET Core compilando-os no formato ReadyToRun (R2R), que é uma compilação AOT (Ahead of Time).
28 | Para utilizar a feature basta adicionar as tags true ao arquivo de configuração.
29 |
30 | Build e Dependências
31 | --------------------
32 |
33 | Agora no Build, todas as dependências externas (NuGet) são copiadas para o seu App. Antes isto acontecia apenas no dotnet publish.
34 |
35 | Local Tools
36 | -----------
37 |
38 | Agora podemos ter comandos específicos locais, assim como temos os globais, mas apenas locais, para determinada aplicação.
39 |
40 | Windows Forms e WPF
41 | -------------------
42 |
43 | Chegou finalmente o suporte a aplicações Windows Forms e WPF (Apenas Windows) com o .NET Core 3.0. Tivemos atualizações para suportá-las no Visual Studio 2019 também, e a adição de dois comandos:
44 | dotnet new wpf
45 | dotnet new winforms
46 |
47 | MSIX
48 | ----
49 |
50 | MSIX é um novo formato de pacote de aplicativos do Windows. Ele pode ser usado para instalar aplicativos (Windows Forms/WPF) do .NET Core 3.0 no Windows 10.
51 |
52 | Compatibilidade com HTTP/2
53 | --------------------------
54 |
55 | O System.Net.Http.HttpClient agora vem com suporte para o HTTP 2!
56 |
57 | Docker e melhorias
58 | ------------------
59 |
60 | Houve melhoras significantes no consumo de memória das apps .NET Core em máquinas Linux e no tamanho também. Em uma demo eles demonstraram uma máquina Alpine com um App .NET Core 3 instalado (RunTime) com apenas 88MB.
61 |
62 | Suporte de GPIO para o Raspberry Pi
63 | -----------------------------------
64 |
65 | Foram lançados dois pacotes para o NuGet que você pode usar para programação de GPIO:
66 | System.Device.Gpio
67 | Iot.Device.Bindings
68 |
69 | Suporte a ARM64 no Linux
70 | ------------------------
71 |
72 | O .NET Core 3.0 adiciona suporte para ARM64 para Linux. Um grande avanço para criação de aplicações para processadores ARM64.
73 |
74 | Resumo do Evento – Live ASP.NET Cast
75 | ------------------------------------
76 | [Clique aqui para assistir](https://www.youtube.com/watch?v=LiDoUVMkT38)
77 |
78 | Vídeos que gostei do .NET Conf
79 | ------------------------------
80 | * [Entity Framework Core 3.0 and Beyond](https://www.youtube.com/watch?v=PXdgyPpfaz4)
81 | * [The Future of the Blazor on the Client](https://www.youtube.com/watch?v=qF6ixMjCzHA)
82 | * [Blazor and Azure Functions for Serverless Websites](https://www.youtube.com/watch?v=noG3rxt38VI)
83 | * [DevOps for the .NET Developers](https://www.youtube.com/watch?v=iQ4HhdxCYN0)
84 | * [Durable Functions 2.0](https://www.youtube.com/watch?v=aHue7XuNYZA)
85 | * [Create Interactive Documentations](https://www.youtube.com/watch?v=XWetRp1f5xg)
86 | * [Azure App Configuration](https://www.youtube.com/watch?v=zRstfC3Nn7M)
87 | * [Azure Services Every .NET Developer Needs to Know](https://www.youtube.com/watch?v=Z9OdipwevSM)
88 | * [Diagnostics Improvements on .NET Core 3.0](https://www.youtube.com/watch?v=fkjetdIdcyg)
89 | * [Secure your NuGet package Ecosystem](https://www.youtube.com/watch?v=UTPct8FKu8I)
90 | * [Building Cloud Native Apps with .NET Core 3.0 and Kubernetes](https://www.youtube.com/watch?v=A0i5BUoKu6s)
91 | * [What`s new in SignalR with .NET Core 3.0](https://www.youtube.com/watch?v=dHiETzo6GB8)
92 |
93 | Fonte:
94 | ------
95 |
96 | [https://docs.microsoft.com/pt-br/dotnet/core/whats-new/dotnet-core-3-0](https://docs.microsoft.com/pt-br/dotnet/core/whats-new/dotnet-core-3-0).
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/hospedagem-gratuita-com-github/index.md:
--------------------------------------------------------------------------------
1 | # Sumário
2 |
3 | 1. [Introdução](#introducao)
4 | 2. [O que são sites estáticos](#o-que-sao-sites-estaticos)
5 | 3. [Criando o site](#criando-o-site)
6 | 4. [Referências](#ref)
7 |
8 |
9 |
10 | # Introdução
11 |
12 | A ferramenta que nos permite publicar sites estáticos gratuitamente no GitHub é conhecida como *GitHub Pages*. Apesar do tamanho limite de 1 GB de armazenamento, 100 GB de banda larga e 10 compilações por hora, é possível utilizar esta ferramenta para diversos fins.
13 |
14 | O GitHub Pages oferece a possíbilidade de publicar sites em repositórios públicos. É possível utilizar repositórios privados e organizacionais também porém em planos não gratuitos. Neste artigo vamos nos atentar a mostrar o funcionamento da ferramenta para título de introdução utilizando um destes meios.
15 |
16 |
17 |
18 | # O que são sites estáticos
19 |
20 | Sites estáticos são aqueles que envolvem HTML (HyperText Markup Language), CSS (Cascading Style Sheets) e JS (JavaScript) sem recursos de gerenciamento de conteúdo. Isto quer dizer que para fazer atualizações ou modificações no site é preciso modificar diretamente o código fonte.
21 |
22 | Com o GitHub Pages você criar um site estático como seu portfólio profissional, site de informações e contato, apresentação do seu projeto e diversas outras usabildiades.
23 |
24 |
25 |
26 | # Criando o site
27 |
28 | Para que seja possível publicar o site no GitHub Pages é necessário acessar o repositório onde este site está localizado. Neste caso usaremos o repositório da organização que criamos nos artigos anteriores.
29 |
30 | 1 - Acesse as configurações do repositório.
31 |
32 | 
33 |
34 | 2 - Encontre a sessão de 'Código e automação' e selecione o item 'Páginas'.
35 |
36 | 
37 |
38 | 3 - Ao chegar em uma página semelhante ao exemplo abaixo você verá a opção de selecionar a fonte onde está localizado o código. Você deve selecionar a branch do repositório que você armazenou o mesmo. Logo abaixo você pode escolher temas que o próprio GitHub oferece para o seu site.
39 |
40 | 
41 |
42 | E então podemos salvar. A partir de agora o conteúdo da branch seleciona será lido pelo github pages e pode ser acessado através do link fornecido ao salvar as configurações que tem o seguinte formato:
43 |
44 | ```
45 | https://nome-da-organizacao.github.io/nome-do-repositorio/
46 | ```
47 |
48 | Agora precisamos de um arquivo chamado `index.html` na raiz desta branch e a partir dele a naveção do site pode ser feita. Você pode adicionar pastas e acessar estas normalmente através das referências dentro do seu código. Para termos de exemplo vamos publicar uma página de exemplo com código estático da W3C.
49 |
50 | Para clonar o repositório para sua máquina utilize em seu terminal o comando:
51 |
52 | ```
53 | git clone https://github.com/repositorio
54 | ```
55 |
56 | Após adicionar os arquivos desejados dentro do repositório comente as mudanças com os comandos:
57 | ```
58 | git add --all
59 | git commit -m "seu comentário"
60 | ```
61 |
62 | E então envie as modificações para o GitHub com o comando:
63 | ```
64 | git push -u origin main
65 | ```
66 | `Nota 1`: Mais detalhes sobre o funcionamento destes comandos podem ser encontrados em artigos relacionados. Os links estão no final deste artigo.
67 |
68 | Ao inserir o código dentro do index.html e subir as modificações para a branch definida anteriormente, o GitHub começará o processo automático de deploy (publicação) que pode ser acompanhado ao clicar na opção de `Actions` no menu superior do repositório.
69 |
70 | 
71 |
72 | Quando o processo for concluído podemos conferir o resultado no link do site estático que nos foi informando durante o processo de habilitação do GitHub Pages. Veja o resultado abaixo:
73 |
74 | 
75 |
76 | # Agora é com você
77 |
78 | Utilize esta ferramenta para publicar seus sites. As pessoas poderão ter a experiência de utilizar algo feito por você e outros desenvolvedores podem se inspirar no resultado do seu trabalho. Crie seu portfólio e adicione o link no seu currículo ou crie o seu currículo online e compartilhe o link. As possibilidades são infinitas.
79 |
80 | # Continue lendo:
81 |
82 | [Git e GitHub - Instalação, Configuração e Primeiros Passos](https://balta.io/blog/git-github-primeiros-passos)
83 |
84 | [Gestão de projetos com GitHub](https://balta.io/blog/gestao-de-projetos-com-github)
85 |
86 | [Gestão de equipes com GitHub](https://balta.io/blog/gestao-de-equipes-com-github)
87 |
88 | ## Cursos relacionados
89 |
90 | `Gratuito` | [Fundamentos do Git e Azure DevOps](https://balta.io/cursos/fundamentos-git-azure-devops)
91 |
92 |
93 |
94 | ## Referências
95 | [Documentação do GitHub](https://docs.github.com/)
96 |
97 | [W3C - Template utilizado neste artigo](https://www.w3schools.com/w3css/tryit.asp?filename=tryw3css_templates_blog&stacked=h)
--------------------------------------------------------------------------------
/flutter-por-onde-comecar/index.md:
--------------------------------------------------------------------------------
1 | Flutter: Por onde começar? Se você se fez esta pergunta então você está no lugar certo, pois este artigo concentra todo material necessário para você dar início a sua jornada como desenvolvedor Mobile.
2 |
3 | O que é o Flutter?
4 | ------------------
5 |
6 | Antes de começar a estudar o Flutter, precisamos entender o que ele é, e para que ele funciona. O Flutter é uma biblioteca que utiliza a linguagem Dart da Google para criação de aplicações móveis Cross Platform.
7 |
8 | Isto significa que podemos criar aplicações para Android e iOS compartilhando parte do código escrito, inclusive há possibilidade de criar aplicações Web e Desktop com Flutter.
9 |
10 | A diferença entre escrever seus Apps com Flutter é que você utiliza uma única linguagem, o Dart, para escrever tanto para iOS quanto Android, e compartilhando código entre ambas.
11 |
12 | O Flutter foi criado pela Google e é relativamente novo, porém ganhou um ótimo mercado no Brasil com adoção da tecnologia por gigantes como NuBank e iFood, além do mercado internacional.
13 |
14 | O Flutter já foi eleito como Framework para criação de aplicações para o Fuchsia, novo sistema operacional da Google, o que mostra que não estão de brincadeira com a tecnologia.
15 |
16 | Flutter: Por onde começar?
17 | --------------------------
18 |
19 | Agora que você já sabe o que é o Flutter, vem a boa notícia, você pode começar a estudar DE GRAÇA aqui mesmo pelo site, fazendo nossos cursos e lendo nossos artigos.
20 |
21 | E aí, está pronto para começar?
22 |
23 | Passo 1 - Instalação
24 | --------------------
25 |
26 | A primeira coisa que você precisa para começar com Flutter é fazer a instalação dos softwares necessários.
27 |
28 | Embora você possa seguir o [guia oficial de instalação do Flutter](https://flutter.dev/) nós preparamos uma versão em português para [instalação do Flutter no MacOs](https://balta.io/blog/comecando-com-flutter-instalacao-macos).
29 |
30 | Você pode utilizar tanto seu telefone quanto um Emulador para rodar seus Apps, tanto no guia oficial quanto em nosso guia, temos este passo-a-passo.
31 |
32 | É importante lembrar que para testar as aplicações iOS, é necessário um MacOs e um iPhone, porém, você pode visualizar elementos seu emulador Android.
33 |
34 | IMPORTANTE: Em Apps mais séries teste sempre nos dispositivos físicos.
35 |
36 | Passo 2 - Dart
37 | --------------
38 |
39 | Parabéns, com tudo instalado é hora de começar a falarmos de código, e a coisa mais importante que precisamos aprender é Linguagem de Programação e Orientação à Objetos.
40 |
41 | Conforme comentamos em nosso [Guia do Aluno](https://balta.io/guia), se você já tem uma base em alguma linguagem de programação e orientação à objetos, tudo fica mais fácil.
42 |
43 | Porém, se você ainda não teve este contato ou se precisa melhorar ainda neste aspecto, não se preocupe.
44 |
45 | [Nosso primeiro curso TOTALMENTE GRATUITO](https://balta.io/cursos/logica-de-programacao-com-dart) vai te ensinar os princípios da linguagem de programação e orientação à objetos já com Dart.
46 |
47 | **[Curso 1: Lógica de Programação com Dart](https://balta.io/cursos/logica-de-programacao-com-dart)**
48 |
49 | Passo 3 - Seu Primeiro App
50 | --------------------------
51 |
52 | Estamos felizes que tenha chego até este ponto, isto significa que você não só venceu os desafios da instalação e configuração, como aprendeu linguagem de programação com Dart.
53 |
54 | Agora chegou a hora de criar seu primeiro App com Flutter e rodar ele no seu emulador ou telefone.
55 |
56 | Não se preocupe se o App ainda é básico, não desista se encontrar erros, o importante é você vencer os desafios, colocar em prática seus conhecimentos sobre Dart e iniciar seus conhecimentos com Flutter.
57 |
58 | [Nosso segundo curso TOTALMENTE GRATUITO](https://balta.io/cursos/criando-seu-primeiro-app-com-flutter) vai te guiar por seu primeiro App, vamos codificar juntos uma aplicação simples mas funcional, que vai te dar uma base sobre Flutter.
59 |
60 | **[Curso 2: Criando seu primeiro App com Flutter](https://balta.io/cursos/criando-seu-primeiro-app-com-flutter)**
61 |
62 | Passo 4 - Desafio final
63 | -----------------------
64 |
65 | SENSACIONAL, esta é a palavra que temos para definir seu esforço até aqui. Neste ponto você nào só venceu os limites da instalação como criou seu primeiro App com Flutter.
66 |
67 | Porém, agora nós temos um desafio ainda maior para você, além de criar uma aplicação, vamos aprender conceitos de organização e padrões de aplicações.
68 |
69 | Estes itens que vão te ajudar por toda sua carreira como desenvolvedor Mobile.
70 |
71 | [Nosso terceiro curso TOTALMENTE GRATUITO](https://balta.io/cursos/flutter-apps-alcool-ou-gasolina) vai te dar toda base necessária para criar Apps básicos de forma organizada.
72 |
73 | **[Curso 3: Flutter Apps: Álcool ou Gasolina](https://balta.io/cursos/flutter-apps-alcool-ou-gasolina)**
74 |
75 | Como continuar?
76 | ---------------
77 |
78 | Se você chegou até aqui, acredito que tivemos uma ótima experiência juntos, correto? Não sei você, mas eu não pretendo para por aqui!
79 |
80 | A nossa **[formação Flutter Mobile Developer](https://balta.io/carreiras/flutter-mobile-developer)** oferece outros cursos gratuitos que podem te ajudar ainda mais.
81 |
82 | Não deixa de conferir nosso material, tenho certeza que vai gostar!
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/aspnet-minimal-signalr/index.md:
--------------------------------------------------------------------------------
1 | No artigo anterior, vimos um pouco sobre Minimal APIs e o novo template Web do ASP.NET. Neste artigo vamos conferir as principais mudanças do SignalR.
2 |
3 | ## Antes de começar
4 | Se você ainda não viu o novo template do ASP.NET Minimal APIs, [clique aqui e confira este artigo](https://balta.io/blog/aspnet-minimal-apis).
5 |
6 | ## O que é o SignalR?
7 | SignalR é a tecnologia da Microsoft, que roda sob o ASP.NET e encapsula chamadas ao WebSocket provendo comunicação em tempo real para seu Frontend (Client) e servidor.
8 |
9 | ### Iniciando o projeto
10 | Vamos começar criando nosso servidor, usando o comando abaixo:
11 | ```
12 | dotnet new web -o SignalServer
13 | cd SignalServer
14 | dotnet add package Microsoft.AspNetCore.SignalR
15 | ```
16 |
17 | O pacote `Microsoft.AspNetCore.SignalR` é tudo que precisamos para trabalhar com SignalR no servidor.
18 |
19 | ## Criando um Hub
20 | Diferente dos projetos ASP.NET MVC, o SignalR utiliza **Hub** ao invés de controladores.
21 |
22 | Os **Hubs** são responsáveis por receber e distribuir mensagens em tempo real. Por sua vez, um **Hub** nada mais é do que uma classe que herda da classe base `Hub`.
23 |
24 | ```csharp
25 | class MyHub : Hub
26 | {
27 | ...
28 | }
29 | ```
30 |
31 | ### IAsyncEnumerable
32 | Se estamos falando em **Tempo Real**, em ficar conectado ao servidor, estamos falando sobre Streaming de dados (Na maioria dos casos), e o C# incluiu nas últimas versões um tipo chamado `IAsyncEnumerable`.
33 |
34 | Desta forma, podemos especificar nosso retorno como um enumerador assíncrono, de modo que possamos fazer streaming dos dados enquanto houverem conexões a este endpoint.
35 |
36 | ```csharp
37 | public async IAsyncEnumerable Streaming(CancellationToken cancellationToken)
38 | {
39 | while (true)
40 | {
41 | yield return DateTime.UtcNow;
42 | await Task.Delay(1000, cancellationToken);
43 | }
44 | }
45 | ```
46 |
47 | É importante notar o uso do `CancelationToken`, que permite que a ação seja cancelada a qualquer momento.
48 |
49 | Em adicional, usamos o `yield` (Produtor) para definir que o retorno é um iterador. Desta forma o cliente pode consumir direto nosso conteúdo, sem necessitar de uma classe para armazenar o estado.
50 |
51 | ## Adicionando SignalR
52 | Para adicionar suporte ao SignalR na nossa aplicação precisamos do `builder.Services.AddSignalR();` e do `app.MapHub("ENDPOINT")`.
53 |
54 | ```csharp
55 | using Microsoft.AspNetCore.SignalR;
56 |
57 | var builder = WebApplication.CreateBuilder(args);
58 | builder.Services.AddSignalR();
59 |
60 | var app = builder.Build();
61 | app.MapHub("/chat");
62 | app.Run();
63 |
64 | ```
65 |
66 | ## Resultado final
67 | O código final. completo do nosso App com SignalR fica assim.
68 |
69 | ```csharp
70 | using Microsoft.AspNetCore.SignalR;
71 |
72 | var builder = WebApplication.CreateBuilder(args);
73 | builder.Services.AddSignalR();
74 |
75 | var app = builder.Build();
76 | app.MapHub("/chat");
77 | app.Run();
78 |
79 |
80 | class MyHub : Hub
81 | {
82 | public async IAsyncEnumerable Streaming(CancellationToken cancellationToken)
83 | {
84 | while (true)
85 | {
86 | yield return DateTime.UtcNow;
87 | await Task.Delay(1000, cancellationToken);
88 | }
89 | }
90 | }
91 | ```
92 |
93 | ### Executando
94 | Agora basta executar o programa usando o comando:
95 | ```
96 | dotnet watch run
97 | ```
98 |
99 | > Não esqueça de anotar a URL na qual seu servidor está rodando. Vamos precisar dela para nos conectar no cliente a seguir.
100 |
101 | ## Trabalhando no Client
102 | Para se conectar ao servidor, vamos criar um Console Application.
103 |
104 | ```
105 | dotnet new console -o SignalClient
106 | cd SignalClient
107 | dotnet add package Microsoft.AspNetCore.SignalR.Client
108 | ```
109 |
110 | Novamente, tudo o que precisamos para consumir um serviço SignalR é o pacote `Microsoft.AspNetCore.SignalR.Client`.
111 |
112 | ### Conectando ao servidor
113 | Para se conectar ao servidor precisamos do `HubConnectionBuilder` apenas.
114 |
115 | ```csharp
116 | using Microsoft.AspNetCore.SignalR.Client;
117 |
118 | var uri = "https://localhost:7182/chat";
119 |
120 | await using var connection = new HubConnectionBuilder().WithUrl(uri).Build();
121 | ```
122 |
123 | Em seguida, podemos iniciar a conexão.
124 |
125 | ```csharp
126 | await connection.StartAsync();
127 | ```
128 |
129 | ### Recebendo dados
130 | Como utilizamos o `IAsyncEnumerable`, para receber os dados, podemos chamar a função `StreamAsync("STREAM")`.
131 |
132 | ```csharp
133 | await foreach (var date in connection.StreamAsync("Streaming"))
134 | {
135 | Console.WriteLine(date);
136 | }
137 | ```
138 |
139 | Como resultado final, temos o seguinte código:
140 |
141 | ```csharp
142 | using Microsoft.AspNetCore.SignalR.Client;
143 |
144 | var uri = "https://localhost:7182/chat";
145 |
146 | await using var connection = new HubConnectionBuilder().WithUrl(uri).Build();
147 |
148 | await connection.StartAsync();
149 |
150 | await foreach (var date in connection.StreamAsync("Streaming"))
151 | {
152 | Console.WriteLine(date);
153 | }
154 | ```
155 | ## Conclusão
156 | Assim como os [Minimal APIs](https://balta.io/blog/aspnet-minimal-apis), outras implementações como ASP.NET SignalR também podem se beneficiar destas mudanças, tornando o ambiente mais simples.
157 |
158 | ### Fontes
159 | * [David Fowler](https://twitter.com/davidfowl)
160 | * [Código Fonte](https://github.com/andrebaltieri/minimal-signalr-example)
--------------------------------------------------------------------------------
/dependency-inversion-principle/index.md:
--------------------------------------------------------------------------------
1 | O DIP ou Dependency Inversion Principle (Princípio da Inversão de Dependência) prega que devemos depender de abstrações e não de implementações.
2 |
3 | ## Dependency Inversion Principle
4 | O princípio da inversão de dependência diz que devemos depender de abstrações (interfaces) ao invés de implementações (classes concretas) a fim de ter um menor acoplamento entre as camadas do sistema.
5 |
6 | Embora esteja relacionado a DI ([Dependency Injection](https://balta.io/blog/dependency-injection)) e IoC ([Inversion of Control](https://balta.io/blog/inversion-of-control)) o DIP é diferente em diversos aspectos.
7 |
8 | ## Dependency Inversion Principle e DI
9 | DI ([Dependency Injection](https://balta.io/blog/dependency-injection)) é uma técnica que auxilia na implementação de outro princípio de design chamado IoC. O DIP se relaciona diretamente com DI, pois podemos usufruir da técnica para gerar dependências (Neste caso de abstrações).
10 |
11 | ### Dependency Injection sem Dependency Inversion Principle
12 | Podemos ter DI sem necessariamente ter o DIP, como mostrado no exemplo abaixo. Neste caso, estamos dependendo de uma abstração concreta e não de uma implementação.
13 |
14 | Isto resolve o problema de reuso de código que poderia ser causado pela responsabilidade de ler o cliente do banco estar no controlador, mas ainda temos um problema aqui.
15 |
16 | ```csharp
17 | public class OrderController : Controller
18 | {
19 | private readonly CustomerRepository _repository;
20 |
21 | public OrderController(CustomerRepository repository)
22 | => _repository = repository;
23 |
24 | [Route("v1/orders")]
25 | [HttpPost]
26 | public async Task Place(PlaceOrderCommand command)
27 | {
28 | // #1 - Recupera o cliente
29 | var customer = await _repository.GetByIdAsync(command.CustomerId);
30 | ...
31 | }
32 | ```
33 |
34 | Neste caso, como dependemos de uma implementação concreta, não temos a flexibilidade para ter diversas implementações deste repositório.
35 |
36 | [](https://balta.io/cursos/dominando-injecao-de-dependencia)
37 |
38 | ## Dependency Inversion Principle e testes de unidade
39 | Mas por que ter diversas implementações de uma mesma interface? Um cenário simples e objetivo são os **testes de unidade**, cujo não devem depender de itens externos.
40 |
41 | Sendo assim, no exemplo anterior, temos uma clara dependências do SQL Server, visto que nossos clientes estão armazenados lá. Mas como podemos executar testes sem depender do SQL Server então?
42 |
43 | **Mocks** ou **Fakes**, ou seja, falsificar uma implementação, fingir que fomos no banco e recuperamos o cliente. Este cenário só é possível mediante a implementação do DIP.
44 |
45 | ## Dependency Inversion Principle na prática
46 | A implementação do DIP é relativamente simples, basta criarmos uma interface `ICustomerRepository` e fazer com que nosso controlador dependa dela e não da implementação concreta (`CustomerRepository`).
47 |
48 | ```csharp
49 | public interface ICustomerRepository
50 | {
51 | Task GetByIdAsync(Guid id);
52 | }
53 | ```
54 |
55 | ```csharp
56 | public class OrderController : Controller
57 | {
58 | private readonly ICustomerRepository _repository;
59 |
60 | public OrderController(ICustomerRepository repository)
61 | => _repository = repository;
62 |
63 | [Route("v1/orders")]
64 | [HttpPost]
65 | public async Task Place(PlaceOrderCommand command)
66 | {
67 | // #1 - Recupera o cliente
68 | var customer = await _repository.GetByIdAsync(command.CustomerId);
69 | ...
70 | }
71 | }
72 | ```
73 | Como as assinaturas são as mesmas, o código no controlador (Exceto a depend6encia) não muda.
74 |
75 | ## Múltiplas implementações
76 | Como vantagem temos a possibilidade de ter múltiplas implementações desta abstração, como no caso `CustomerRepository` e `FakeCustomerRepository`.
77 |
78 | ```csharp
79 | public class CustomerRepository : ICustomerRepository
80 | {
81 | public async Task GetByIdAsync(Guid id)
82 | {
83 | var using (var conn = new SqlConnection("CONN_STRING"))
84 | const query = "SELECT * FROM CUSTOMER WHERE ID=@id";
85 | return customer = conn.FirstOrDefaultAsync(query, new { id = Id });
86 | }
87 | }
88 | ```
89 |
90 | ```csharp
91 | public class FakeCustomerRepository : ICustomerRepository
92 | {
93 | public async Task GetByIdAsync(Guid id)
94 | {
95 | await Task.Delay(0);
96 | return new Customer("André", "Baltieri");
97 | }
98 | }
99 | ```
100 | ## Testes de Unidade
101 | Como nosso controlador depende de uma abstração `ICustomerRepository`, ele aceita tanto um `CustomerRepository` quanto um `FakeCustomerRepository` como entrada, nos permitindo **mockar** os testes.
102 |
103 | ```csharp
104 | [TestMethod]
105 | public void ShouldPlaceAnOrder() {
106 | IDeliveryService service = new FakeDeliveryService();
107 | var controller = new OrderController(service);
108 | ...
109 | }
110 | ```
111 |
112 | Desta forma aplicamos o DIP e ainda temos testes livres de dependências externas.
113 |
114 | ## Conclusão
115 | Dependency Inversion Principle é um dos cinco princípios do SOLID, que tem uma implementação relativamente fácil e que nos auxilia a desacoplar camadas do sistema.
116 |
--------------------------------------------------------------------------------
/novidades-aspnet-7/index.md:
--------------------------------------------------------------------------------
1 | O ASP.NET 7 já tem data prevista e os primeiros Previews já estão disponíveis. Neste artigo vamos ver as primeiras mudanças que vem por aí na nova versão.
2 |
3 | ## Instalando o .NET 7
4 | Até a escrita deste artigo o .NET 7 está em sua segunda Preview e para conferir todas as novidades do ASP.NET 7 você precisa [**instalar o SDK desta versão**](https://dotnet.microsoft.com/en-us/download/dotnet/7.0).
5 |
6 | Não se preocupe pois as versões anteriores do .NET na sua máquina não serão alteradas, o .NET roda lado a lado, não sendo necessário remover instalações antigas.
7 |
8 | ## Atualizando seu projeto
9 | Caso tenha criado algum projeto em .NET 6 e queira atualizar para o 7, basta alterar as dependências no arquivo `.csproj` apontando para versão 7.
10 |
11 | * Microsoft.AspNetCore.* => 7.0.0-preview.2.*.
12 | * Microsoft.Extensions.* => 7.0.0-preview.2.*.
13 |
14 | ## Inferência de parâmetros nas ações dos Controllers
15 | Se você conferiu nosso [**artigo sobre Minimal APIs**](https://balta.io/blog/aspnet-minimal-apis), você provavelmente notou que não utilizamos `[FromServices]`, `[FromBody]`, `[From*]` nos parâmetros dos métodos que respondem as rotas.
16 |
17 | Isto por que o ASP.NET infere estes parâmetros, fazendo uma busca nas dependências, corpo da requisição, cabeçalho da requisição e até na Query String.
18 |
19 | Este recurso também estará presente no ASP.NET 7, não sendo mais necessário especificar de onde o parâmetro vem. Pelo menos na maioria dos casos, não.
20 |
21 | ```csharp
22 | Services.AddScoped();
23 |
24 | [Route("[controller]")]
25 | [ApiController]
26 | public class MyController : ControllerBase
27 | {
28 | // Ambos métodos irão funcionar
29 | public ActionResult GetWithAttribute([FromServices]SomeCustomType service) => Ok();
30 | public ActionResult Get(SomeCustomType service) => Ok();
31 | }
32 | ```
33 |
34 | Caso queira desabilitar este comportamento, basta setar a propriedade `DisableImplicitFromServicesParameters` para `true` nas configurações da sua API, como demonstrado abaixo.
35 |
36 | ```csharp
37 | Services.Configure(options =>
38 | {
39 | options.DisableImplicitFromServicesParameters = true;
40 | })
41 | ```
42 |
43 | ## SignalR agora suporta DI
44 | O SignalR também receberá uma atualização, permitindo a injeção de dependências nos métodos dos Hubs, e assim como no ASP.NET, não necessitamos do `[FromServices]`.
45 |
46 | ```csharp
47 | Services.AddScoped();
48 |
49 | public class MyHub : Hub
50 | {
51 | // SomeCustomType vem da DI por padrão agora
52 | public Task Method(string text, SomeCustomType type) => Task.CompletedTask;
53 | }
54 | ```
55 | Caso queira desabilitar este comportamento, basta setar a propriedade para `true` nas configurações da sua API, como demonstrado abaixo.`DisableImplicitFromServicesParameters`
56 |
57 | ```csharp
58 | services.AddSignalR(options =>
59 | {
60 | options.DisableImplicitFromServicesParameters = true;
61 | });
62 | ```
63 |
64 | Caso queira explicitar a origem do parâmetro, você ainda pode utilizar o `[FromServices]` também, sem problema algum.
65 |
66 | ```csharp
67 | public class MyHub : Hub
68 | {
69 | public Task Method(string arguments, [FromServices] SomeCustomType type);
70 | }
71 | ```
72 |
73 | ## Descrição e sumário nas Minimal APIs
74 | Uma adição nas Minimal APIs é a possibilidade de informarmos uma descrição e/ou sumário a um método, que poderá ser refletido posteriormente na documentação da API.
75 |
76 | ```csharp
77 | app.MapGet("/hello", () => ...)
78 | .WithDescription("Sends a request to the backend HelloService to process a greeting request.");
79 |
80 | // Ou
81 |
82 | app.MapGet("/hello", [EndpointSummary("Sends a Hello request to the backend")]() => ...)
83 |
84 | ```
85 |
86 | ## Arrays e StringValues nas Minimal APIs
87 | Outra adição as Minimal APIs será a possibilidade de fazer bind dos valores do cabeçalho HTTPS e Query Strings para arrays de tipos primitivos ou StringValues.
88 |
89 | ```csharp
90 | // Bind query string values to a primitive type array
91 | // GET /tags?q=1&q=2&q=3
92 | app.MapGet("/tags", (int[] q) => $"tag1: {q[0]} , tag2: {q[1]}, tag3: {q[2]}")
93 |
94 | // Bind to a string array
95 | // GET /tags?names=john&names=jack&names=jane
96 | app.MapGet("/tags", (string[] names) => $"tag1: {names[0]} , tag2: {names[1]}, tag3: {names[2]}")
97 |
98 | // Bind to StringValues
99 | // GET /tags?names=john&names=jack&names=jane
100 | app.MapGet("/tags", (StringValues names) => $"tag1: {names[0]} , tag2: {names[1]}, tag3: {names[2]}")
101 | ```
102 | No caso das Query Strings podemos inclusive fazer bind de valores para tipos complexos.
103 |
104 | ```csharp
105 | // Bind to an array of a complex type
106 | // GET /tags?tags=trendy&tags=hot&tags=spicy
107 | app.MapGet("/tags", (Tag[] tags) =>
108 | {
109 | return Results.Ok(tags);
110 | });
111 |
112 | ...
113 |
114 | class Tag
115 | {
116 | public string? TagName { get; init; }
117 |
118 | public static bool TryParse(string? tagName, out Tag tag)
119 | {
120 | if (tagName is null)
121 | {
122 | tag = default;
123 | return false;
124 | }
125 |
126 | tag = new Tag { TagName = tagName };
127 | return true;
128 | }
129 | }
130 | ```
131 |
132 | ## Customizar o consentimento dos Cookies
133 | Teremos a adição da propriedade `CookiePolicyOptions.ConsentCookieValue` para acompanhar e customizar o consentimento do usuário em relação aos Cookies que armazenamos.
134 |
135 | ## Fonte
136 | * https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-preview-2
--------------------------------------------------------------------------------
/descomplicando-o-model-biding-no-aspnet-core/index.md:
--------------------------------------------------------------------------------
1 | # Sumário
2 |
3 | 1. [Introdução](#introducao)
4 | 2. [[Bind] - Obtendo propriedades específicas](#bind-obtendo-propriedades-especificas)
5 | 3. [[FromQuery] - Obtendo valores da cadeia de caracteres de consulta](#fromquery-obtendo-valores-da-cadeia-de-caracteres-de-consulta)
6 | 4. [[FromRoute] - Obtendo valores de dados de rota](#from-route-obtendo-valores-de-dados-de-rota)
7 | 5. [[FromForm] - Obtendo valores de campos de formularios postado](#fromform-obtendo-valores-de-campos-de-formularios-postados)
8 | 6. [[FromBody] - Obtendo valores do corpo da solicitação](#frombody-obtendo-valores-do-corpo-da-solicitacao)
9 | 7. [Continue lendo](#continue-lendo)
10 | 8. [Referências](#ref)
11 |
12 |
13 |
14 |
15 | # Introdução
16 |
17 | Este artigo tem o objetivo de introduzir às possíveis formas de manipular informações utilizando o ModelBinding.
18 |
19 |
20 |
21 | # [Bind] - Obtendo propriedades específicas
22 |
23 | É possível que durante o processo de desenvolvimento surja situações onde seja necessário obter valores de propriedades especificas e ignorar outras. Para isto utilizamos o `[Bind]`. Assim ignorando propriedades não especificadas.
24 |
25 | Código:
26 | ```csharp
27 | [HttpPost]
28 | public IActionResult OnPost([Bind("Name, Email, IsActive")] User user)
29 | => throw new NotImplementedException();
30 | ```
31 |
32 | No código acima pode-se ver o método `OnPost` que deve receber um usuário como paranêtro. Mas como temos interesse apenas em três campos específicos, declaramos eles com o Bind e assim receberemos os demais retornaram nulos ou caso tenham, um valor padrão.
33 |
34 | `Nota 1:` *Este comportamento relacionado aos atributos não especificados faz com que o [Bind] não seja uma boa opção em casos de edição já que ele não mantém o valor anterior das propriedades não especificadas.*
35 |
36 |
37 |
38 | # [FromQuery] - Obtendo valores da cadeia de caracteres de consulta
39 |
40 | Antes de obter os valores a partir de uma cadeia de caracteres de consulta vamos deixar claro o que ela é. A cadeia de caracteres de consulta ou `QueryString` é um modelo para atribuição de valores a parâmetros utilizando a URL (Uniform resource locator).
41 |
42 | Exemplo: `https://seudominio.com/controller/action/?Name=Joao&Email=mail@mail.com&IsActive=false&LastUpdateDate=null`
43 |
44 | O trecho `?Name=Joao%Email=mail@mail.com` é a QueryString. Podemos identificá-la a partir do sinal de interrogação. Depois Temos os parâmetros no formato: `Parâmetro=valor` e separados pelo `&`.
45 |
46 | Bem, então para recuperar os dados que estão sendo transportados na QueryString e converter em um objeto do tipo `User` é necessário utilizar o atributo `[FromQuery]`:
47 |
48 | Código:
49 | ```csharp
50 | [HttpPost]
51 | public IActionResult OnPost([FromQuery] User user)
52 | => throw new NotImplementedException();
53 | ```
54 |
55 | Com o código acima o atributo `[FromQuey]` busca vincular os valores dos parâmetros da QueryString com propriedades equivalentes (mesmo nome e tipo compatível) no objeto `User`.
56 |
57 |
58 |
59 | # [FromRoute] - Obtendo valores de dados de rota
60 |
61 | Aqui também recuperamos dados a partir da rota, mas disponíveis de forma diferente do `[FromQuey]` que foi mostrado anteriormente. Observe a URL abaixo
62 |
63 | URL: `https://seudominio.com/controller/action/mail@mail.com`
64 |
65 | Para recuperar o endereço de e-mail informado na URL podemos usar o `[FromRoute]`. Veja o exemplo abaixo:
66 |
67 | ```csharp
68 | [HttpPost("controller/action/{email}")]
69 | public IActionResult Action([FromRoute] string email)
70 | => throw new NotImplementedException();
71 | ```
72 |
73 | O `[HttpPost]` aqui recebe um modelo de rota que é complementado por um atributo que está sendo aguardado.
74 |
75 | `Nota 2:` *É possível melhorar a definição da rota. Um assunto que não será abordado neste artigo para manter o foco no na introdução ao ModelBinding.*
76 |
77 |
78 |
79 | # [FromForm] - Obtendo valores de campos de formulários postados
80 |
81 | Como o nome do parâmetro já sugere, ele é utilizado para recuperar valores de um formulário. Seguindo o memo padrão dos parâmetros anteriores, é necessário que os nomes coincidam. No código o uso dele fica assim:
82 |
83 | ```csharp
84 | [HttpPost]
85 | public IActionResult ActionName([FromForm] User user)
86 | => throw new NotImplementedException();
87 | ```
88 |
89 | `Nota 3:` Por ser característico (recuperar valores apenas de formulários postados) o `[FromForm]` aceita apenas métodos `[HttpPost].
90 |
91 | # [FromBody] - Obtendo valores do corpo da solicitação
92 | Caso a solicitação tenha um formato como por exemplo `JSON` você pode utilizar o `[FromBody]` para recuperar informações da mesma.
93 | Exemplo de entrada JSON:
94 | ```json
95 | {
96 | "Name": "Joao Teste",
97 | "Email": "mail@mail.com"
98 | }
99 | ```
100 |
101 |
102 | A declaração no código para leitura dos valores fica da seguinte forma:
103 |
104 | ```csharp
105 | [HttpPost]
106 | public ActionResult ActionName([FromBody] User user)
107 | => throw new NotImplementedException();
108 | ```
109 |
110 |
112 |
113 | # Continue lendo:
114 |
115 | [Logs no ASP.NET com Serilog](https://balta.io/blog/aspnet-serilog)
116 |
117 | [Criando uma API do zero com .NET Core 3.1 e EF Core](https://balta.io/blog/criando-api-zero-dotnet-core-3-1-ef-core)
--------------------------------------------------------------------------------
/mudancas-ef-core-5/index.md:
--------------------------------------------------------------------------------
1 | Mudanças no EF Core 5 estão a caminho, mas o que de fato devemos esperar delas? Será que as preces da comunidade serão ouvidas?
2 |
3 | O que é um ORM?
4 | ---------------
5 |
6 | Acho que o primeiro item que devemos pontuar antes de prosseguir é o que de fato é um ORM. ORM é a sigla para Object/Relational Mapping ou mapeamento objeto/relacional.
7 |
8 | Sua função é mapear o resultado que recebemos de um banco de dados relacional para um objeto. Note que eu disse OBJETO e não entidade, ou seja, pode ser um DTO, uma entidade anêmica, qualquer coisa.
9 |
10 | Caso queira saber mais sobre Modelagem de Domínios Ricos, acesse meu curso GRATUITO sobre o assunto [clicando aqui](https://balta.io/cursos/modelando-dominios-ricos).
11 |
12 | Criação do EF Core
13 | ------------------
14 |
15 | Na versão 1.x do .NET Core muita coisa foi prometida, mas como as mudanças eram muitas, confesso que minha expectativa não estava lá em cima, pois eu sabia que o .NET Core ainda não estava maduro e o EF Core muito menos.
16 |
17 | Porém, o item que mais me deixou desapontado foi o mapeamento NxN, que antes dado por Navigation Properties agora exigia uma classe exclusiva para isto.
18 |
19 | Em termos de modelagem, isto é muito ruim. Sabemos que não conseguimos ter o cenário perfeito de OOP usando um ORM, mas afetar desta forma a modelagem chega a doer na alma.
20 |
21 | Na versão 2.x vieram várias melhorias de performance, query, e na 3.x isto continuou, mas nada do NxN mudar, pior, o time do EF disse publicamente que ele estava pronto!
22 |
23 | Proposta do EF Core
24 | -------------------
25 |
26 | Foi então que decidi parar de brigar e assumir que a proposta do EF Core é mais Data Driven do que Domain Driven. Olhando o cenário NxN podemos ver claramente uma alusão aos relacionamentos de bancos de dados e não a OOP.
27 |
28 | Encarar desta forma facilitou encaixar o uso do EF Core no dia-a-dia, ou seja, em cenário Data Driven ele brilha, em cenários focados em domínios ricos, ou usamos outra coisa, ou desmanchamos nossas entidades.
29 |
30 | Se quiser saber mais sobre a criação de APIs Data Driven com ASP.NET Core 3 e EF Core 3, acesse meu curso [clicando aqui](https://balta.io/cursos/criando-apis-data-driven-com-aspnet-core-3-e-ef-core-3).
31 |
32 | Time não ouvia a comunidade
33 | ---------------------------
34 |
35 | Outro ponto que me incomodava bastante é que muitas das features que vou comentar abaixo estão como “sugestão” no GitHub do EF Core há tempos, mas vinham sendo ignoradas pelo time.
36 |
37 | Não estou julgando pois não se internamente como acontecem as coisas lá, mas sei que a implementação destas features na nova versão mostra que o time está se posicionando diferente, ouvindo mais a comunidade.
38 |
39 | Mudanças no EF Core 5
40 | ---------------------
41 |
42 | A primeira mudança é na versão, pois não teremos o EF Core 4.x, pularemos para o EF Core 5 para acompanhar o .NET Core 5.
43 |
44 | Embora a mudança seja grande, não haverá muitas breaking changes aparentemente e vale salientar que estas informações ainda são BEM RECENTES e muita coisa pode mudar.
45 |
46 | Sem mais delongas, vamos as 6 mudanças mais aguardadas no Entity Framework Core 5.
47 |
48 | ### Mudanças no EF Core 5: Many-to-Many
49 |
50 | Eu sei que deveria deixar esta feature para o fim, mas não estou aguentando de felicidade. Finalmente teremos uma mudança no modelo de mapeamento NxN, com a volta dos Navigation Properties.
51 |
52 | O modelo atual ainda será suportado, porém teremos a alternativa de fazer como antigamente, apenas tendo duas listas uma em cada entidade, sendo gerada uma terceira tabela apenas a nível de banco de dados.
53 |
54 | ### Mudanças no EF Core 5: Table per Type
55 |
56 | Outra mudança legal é a possibilidade de mapear classes abstratas (Tipos) como tabela. Esta feature permite que trabalhemos com herança de forma melhor no EF caso seja necessário separar apenas o tipo em uma tabela a parte.
57 |
58 | ### Mudanças no EF Core 5: Query nos Includes
59 |
60 | Fazer consultas quando há Include envolvido é sempre um desafio. Muitas vezes partimos para o LINQ ou mesmo para o Dapper ou ADO, mas agora isto também será melhorado.
61 |
62 | Será incluso o ThenInclude (Nome temporário) para que possamos aninhar Includes e também a possibilidade de consultas dentro do próprio Include.
63 |
64 | ### Mudanças no EF Core 5: Migration fora do Startup
65 |
66 | Para os fãs de DevOps, os Migrations serão desacoplados da aplicação, tornando fácil executar a migração.
67 |
68 | Hoje normalmente o Migration é feito no Startup do App e traz muitos problemas, incluindo a necessidade de um novo deploy para mudanças na migração.
69 |
70 | Com as Migrations fora do App, podemos incluí-las no processo de deployment, como deve ser de fato.
71 |
72 | ### Mudanças no EF Core 5: Plataform Experience
73 |
74 | Outro tópico comentado é sobre melhorias no uso do EF com Xamarin, Blazor, WinForms/WPF, mas este tópico vou ficar devendo pois não tenho conhecimento para falar sobre.
75 |
76 | Abaixo deixo o link para o artigo oficial, você pode obter mais informações lá!
77 |
78 | ### Mudanças no EF Core 5: Melhorias nas queries/Performance
79 |
80 | Além dos tópicos que mencionei, teremos melhorias nas queries e performance, assim como o time vem fazendo nas versões anteriores.
81 |
82 | Não sei o que esperar, mas acho que não será algo muito grande, serão pontos específicos e vamos melhorando o framework aos poucos!
83 |
84 | Fonte
85 | -----
86 |
87 | [Plan for Entity Framework Core 5.0](https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/plan)
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/csharp-deconstruct/index.md:
--------------------------------------------------------------------------------
1 | O C# conta com um recurso parecido com o do JavaScript onde podemos desconstruir um objeto e obter de forma fácil e simples suas propriedades.
2 |
3 | ## Deconstruct
4 | O primeiro passo é entender o que é o método `Deconstruct` que não deve ser confundido com o método destrutor do objeto (`~Metodo()`). O nome **deconstruct** significa desconstruir, que é exatamente o que queremos aqui.
5 |
6 | Nos artigos anteriores [**falamos sobre métodos de extensão (Extension Methods)**](https://balta.io/blog/csharp-extension-methods) e como podemos extender tipos **built-in** do .NET de forma simples e fácil. O `Deconstruct` funcionará de forma similar.
7 |
8 | Na verdade o `Deconstruct` deve ser inserido dentro de uma classe de extensão, como fazemos com os **Extension Methods**, então vamos começar criando uma classe estática que é obrigatória neste caso.
9 |
10 | ```csharp
11 |
12 | public static class DateTimeExtensions
13 | {
14 | // ...
15 | }
16 | ```
17 | ### Implementação
18 | A diferença entre um método de extensão comum e um `Deconstruct` é o nome deste. Neste caso, o nome **obrigatóriamente** deve ser `Deconstruct`, como mostrado abaixo.
19 |
20 | ```csharp
21 | public static class DateTimeExtensions
22 | {
23 | public static void Deconstruct()
24 | {
25 | // ...
26 | }
27 | }
28 | ```
29 |
30 | Como pudemos notar, estamos trabalhando em uma extensão para o `DateTime`, então vamos seguir com o método como se de fato estivessemos escrevendo um **Extension Method**, que exige um parâmetro de entrada com a palavra `this` na frente.
31 |
32 | ```csharp
33 | public static class DateTimeExtensions
34 | {
35 | public static void Deconstruct(this DateTime dateTime)
36 | {
37 | // ...
38 | }
39 | }
40 | ```
41 |
42 | Além do nome `Deconstruct` obrigatório, temos que retornar um valor neste método, e aqui vem a parte legal da coisa. O ato de desconstruir um objeto, remete ao desmembramento do mesmo, em variáveis.
43 |
44 | Nos artigos anteriores, [**vimos como trabalhar com Tuplas**](https://balta.io/blog/csharp-tuple), que serão utilizadas aqui. Então nada melhor que desmembrar nossa Data/Hora em uma tupla que retorna ano, mês e dia de forma separada.
45 |
46 | ```csharp
47 | public static class DateTimeExtensions
48 | {
49 | public static void Deconstruct(
50 | this DateTime dateTime,
51 | out int year, out int month, out int day)
52 | {
53 | // ...
54 | }
55 | }
56 | ```
57 |
58 | Note que fizemos uso da palavra reservada `out`, uma vez que o método `Deconstruct` é do tipo `void` e não tem um retorno específico. Neste caso, o `out` vai gerar três variáveis para nós, `year`, `month` e `day`, todas como `int`.
59 |
60 | Agora tudo que precisamos fazer é assimilar as variáveis aos valores do `DateTime` que recebemos como entrada. Estes valores serão automaticamente expostos de forma desconstruída.
61 |
62 | ```csharp
63 | public static class DateTimeExtensions
64 | {
65 | public static void Deconstruct(
66 | this DateTime dateTime,
67 | out int year, out int month, out int day)
68 | {
69 | year = dateTime.Year;
70 | month = dateTime.Month;
71 | day = dateTime.Day;
72 | }
73 | }
74 | ```
75 |
76 |
77 | ### Melhorando o código
78 | Antes de prosseguir, podemos melhorar nosso código utilizando as Tuplas. Aqui podemos criar um conjunto com os três valores que utilizamos no `out` e em seguida fazer a assimilação em grupo dos valores do `DateTime` para estes.
79 |
80 | ```csharp
81 | public static class DateTimeExtensions
82 | {
83 | public static void Deconstruct(
84 | this DateTime dateTime,
85 | out int year, out int month, out int day)
86 | {
87 | (year, month, day) = (dateTime.Year, dateTime.Month, dateTime.Day);
88 | }
89 | }
90 | ```
91 | E claro, para melhorar ainda mais nosso código, como temos apenas uma linha de código no método `Deconstruct`, podemos torná-lo um **Expression Body**, usando `=>` e retornando o resultado diretamente.
92 |
93 | ```csharp
94 | public static class DateTimeExtensions
95 | {
96 | public static void Deconstruct(
97 | this DateTime dateTime,
98 | out int year, out int month, out int day)
99 | => (year, month, day) = (dateTime.Year, dateTime.Month, dateTime.Day);
100 | }
101 | ```
102 |
103 | ## Utilizando o Deconstruct
104 | Para utilizar o `Deconstruct`, basta assimilar uma **Data/Hora** a uma variável que seja uma Tupla esperando três valores (Assim como definimos nos `out`).
105 |
106 | ```csharp
107 | var (y, m, d) = DateTime.Now;
108 |
109 | Console.WriteLine(y);
110 | Console.WriteLine(m);
111 | Console.WriteLine(d);
112 | ```
113 |
114 | Note que o nome das variáveis não importam, tanto que definimos `y`, `m` e `d` para elas. No entando, elas serão assimiladas conforme a ordem dos `out`, que no nosso caso é `year` (Ano), `month` (Mês) e `day` (Dia).
115 |
116 | Desta forma, não adianta inverter a ordem na hora de receber os valores (Como mostrado abaixo), você estará mudando apenas o nome das variáveis (E confundindo outras pessoas). A ordem sempre será ANO-MÊS-DIA conforme definida nos `out` do `Deconstruct`.
117 |
118 | ```csharp
119 | var (day, year, month) = DateTime.Now;
120 |
121 | Console.WriteLine(day);
122 | Console.WriteLine(year);
123 | Console.WriteLine(month);
124 | ```
125 |
126 | Particularmente gosto de criar nomes mais intuitivos, mesmo que maiores, então tento nomear as variáveis das tuplas de acordo com os `out`, tendo como resultado final o código abaixo.
127 |
128 | ```csharp
129 | var (year, month, day) = DateTime.Now;
130 |
131 | Console.WriteLine(year);
132 | Console.WriteLine(month);
133 | Console.WriteLine(day);
134 | ```
135 |
136 | ## Conclusão
137 | Como pudemos notar, o C# possui inúmeras funcionalidades escondidas e o `Deconstruct` é uma delas, que pode agregar muito valor e facilitar muito nosso código.
--------------------------------------------------------------------------------