Browse Source

Merge remote-tracking branch 'abpframework/dev' into Translate

pull/1910/head
梁士伟 7 years ago
parent
commit
adee3a840e
  1. 4
      README.md
  2. 13
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/pt-BR.json
  3. 60
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/pt-BR.json
  4. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
  5. 31
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/pt-BR.json
  6. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json
  7. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/pt-BR.json
  8. 9
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  9. 30
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json
  10. 9
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json
  11. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/pt-BR.json
  12. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/pt-BR.json
  13. 160
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json
  14. 2
      common.props
  15. 10
      common.test.props
  16. 35
      docs/cs/Best-Practices/PostgreSQL-Integration.md
  17. BIN
      docs/cs/Best-Practices/images/postgresql-delete-initial-migrations.png
  18. BIN
      docs/cs/Best-Practices/images/postgresql-update-database.png
  19. 61
      docs/cs/Dapper.md
  20. 126
      docs/cs/Getting-Started-Angular-Template.md
  21. 14
      docs/cs/docs-nav.json
  22. 5
      docs/docs-langs.json
  23. 3
      docs/en/AspNetCore/JavaScript-API/Auth.md
  24. 24
      docs/en/AspNetCore/JavaScript-API/Index.md
  25. 370
      docs/en/Authorization.md
  26. 21
      docs/en/Blog-Posts/2019-09-25 v0_21_Release/Post.md
  27. BIN
      docs/en/Blog-Posts/2019-09-25 v0_21_Release/volosoft-booth.png
  28. 82
      docs/en/Caching.md
  29. 4
      docs/en/Getting-Started-Angular-Template.md
  30. 4
      docs/en/Modules/Index.md
  31. 3
      docs/en/Modules/Permission-Management.md
  32. 11
      docs/en/Multi-Tenancy.md
  33. 257
      docs/en/Object-To-Object-Mapping.md
  34. 2
      docs/en/Startup-Templates/Module.md
  35. 10
      docs/en/docs-nav.json
  36. BIN
      docs/en/images/authorization-new-permission-ui-hierarcy.png
  37. BIN
      docs/en/images/authorization-new-permission-ui-localized.png
  38. BIN
      docs/en/images/authorization-new-permission-ui.png
  39. 31
      docs/es/Index.md
  40. 3
      docs/pt-BR/Aspect-Oriented-Programming.md
  41. 3
      docs/pt-BR/Audit-Logging.md
  42. 3
      docs/pt-BR/Authorization.md
  43. 3
      docs/pt-BR/AutoMapper-Integration.md
  44. 3
      docs/pt-BR/Background-Jobs-Hangfire.md
  45. 3
      docs/pt-BR/Background-Jobs-RabbitMq.md
  46. 149
      docs/pt-BR/CLI.md
  47. 3
      docs/pt-BR/Caching.md
  48. 60
      docs/pt-BR/Contribution/Index.md
  49. 3
      docs/pt-BR/CorrelationId.md
  50. 3
      docs/pt-BR/Data-Filtering.md
  51. 3
      docs/pt-BR/Data-Seeding.md
  52. 3
      docs/pt-BR/Data-Transfer-Objects.md
  53. 3
      docs/pt-BR/Distributed-Event-Bus.md
  54. 3
      docs/pt-BR/Domain-Services.md
  55. 3
      docs/pt-BR/Dynamic-Proxying-Interceptors.md
  56. 3
      docs/pt-BR/Emailing.md
  57. 3
      docs/pt-BR/Event-Bus.md
  58. 3
      docs/pt-BR/Extension-Methods-And-Helpers.md
  59. 126
      docs/pt-BR/Getting-Started-Angular-Template.md
  60. 183
      docs/pt-BR/Getting-Started-AspNetCore-Application.md
  61. 102
      docs/pt-BR/Getting-Started-AspNetCore-MVC-Template.md
  62. 181
      docs/pt-BR/Getting-Started-Console-Application.md
  63. 3
      docs/pt-BR/Guid-Generation.md
  64. 31
      docs/pt-BR/Index.md
  65. 3
      docs/pt-BR/Integration-Tests.md
  66. 3
      docs/pt-BR/Local-Event-Bus.md
  67. 195
      docs/pt-BR/Localization.md
  68. 27
      docs/pt-BR/Nightly-Builds.md
  69. 3
      docs/pt-BR/Object-To-Object-Mapping.md
  70. 3
      docs/pt-BR/SMS-Sending.md
  71. 3
      docs/pt-BR/Settings.md
  72. 3
      docs/pt-BR/Specifications.md
  73. 275
      docs/pt-BR/Startup-Templates/Application.md
  74. 7
      docs/pt-BR/Startup-Templates/Index.md
  75. 161
      docs/pt-BR/Startup-Templates/Module.md
  76. 3
      docs/pt-BR/Testing.md
  77. 661
      docs/pt-BR/Tutorials/Angular/Part-I.md
  78. 582
      docs/pt-BR/Tutorials/Angular/Part-II.md
  79. 181
      docs/pt-BR/Tutorials/Angular/Part-III.md
  80. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-actions-buttons.png
  81. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-angular-file-tree.png
  82. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-backend-solution-v2.png
  83. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-book-list.png
  84. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-confirmation-popup.png
  85. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-creating-book-list-terminal.png
  86. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-creating-books-module-terminal.png
  87. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-edit-modal.png
  88. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-empty-new-book-modal.png
  89. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-final-actions-dropdown.png
  90. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-initial-book-list-page.png
  91. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-initial-books-page-with-layout.png
  92. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-initial-books-page.png
  93. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-new-book-form-v2.png
  94. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-new-book-form.png
  95. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-service-terminal-output.png
  96. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-swagger-api.png
  97. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-test-explorer.png
  98. BIN
      docs/pt-BR/Tutorials/Angular/images/bookstore-test-projects-v3.png
  99. 462
      docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-I.md
  100. 466
      docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-II.md

4
README.md

@ -5,7 +5,7 @@
[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.Core.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds)
This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://abp.io/blog/abp/Abp-vNext-Announcement).
This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://blog.abp.io/abp/Abp-vNext-Announcement).
See the official [web site (abp.io)](https://abp.io/) for more information.
@ -21,7 +21,7 @@ See the <a href="https://docs.abp.io/" target="_blank">documentation</a>.
#### Pre Requirements
- Visual Studio 2019 16.1.0+
- Visual Studio 2019 16.3.0+
#### Framework

13
abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/pt-BR.json

@ -0,0 +1,13 @@
{
"culture": "pt-BR",
"texts": {
"Account": "Conta",
"Welcome": "Bem-vindo",
"UseOneOfTheFollowingLinksToContinue": "Use um dos seguintes links para continuar",
"FrameworkHomePage": "Página inicial do Framework",
"FrameworkDocumentation": " Documentação do Framework",
"OfficialBlog": "Blog oficial",
"CommercialHomePage": "Página inicial comercial",
"CommercialSupportWebSite": "Site de suporte comercial"
}
}

60
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/pt-BR.json

@ -0,0 +1,60 @@
{
"culture": "pt-BR",
"texts": {
"Permission:NpmPackages": "Pacotes NPM",
"Permission:NugetPackages": "Pacotes Nuget",
"Permission:Maintenance": "Manutenção",
"Permission:Maintain": "Manter",
"Permission:ClearCaches": "Limpar caches",
"Permission:Modules": "Módulos",
"Permission:Packages": "Pacotes",
"Permission:Edit": "Editar",
"Permission:Delete": "Excluir",
"Permission:Create": "Criar",
"Menu:Packages": "Pacotes",
"NpmPackageDeletionWarningMessage": "Este pacote NPM será excluído. Você confirma isso?",
"NugetPackageDeletionWarningMessage": "Este pacote Nuget será excluído. Você confirma isso?",
"ModuleDeletionWarningMessage": "Este módulo será excluído. Você confirma isso?",
"Name": "Nome",
"DisplayName": "Mostrar nome",
"ShortDescription": "Breve descrição",
"NameFilter": "Nome",
"CreationTime": "Hora da criação",
"IsPro": "É profissional",
"EfCoreConfigureMethodName": "Configurar nome do método",
"IsProFilter": "É profissional",
"ApplicationType": "Tipo de aplicativo",
"Target": "Objetivo",
"TargetFilter": "Objetivo",
"ModuleClass": "Classe do módulo",
"NugetPackageTarget.DomainShared": "Domínio compartilhado",
"NugetPackageTarget.Domain": "Domínio",
"NugetPackageTarget.Application": "Aplicativo",
"NugetPackageTarget.ApplicationContracts": "Contratos de aplicativos",
"NugetPackageTarget.HttpApi": "Http Api",
"NugetPackageTarget.HttpApiClient": "Cliente HTTP da API",
"NugetPackageTarget.Web": "Web",
"NugetPackageTarget.EntityFrameworkCore": "EntityFramework Core",
"NugetPackageTarget.MongoDB": "MongoDB",
"Edit": "Editar",
"Delete": "Excluir",
"Refresh": "Atualizar",
"NpmPackages": "Pacotes NPM",
"NugetPackages": "Pacotes Nuget",
"NpmPackageCount": "Contagem de pacotes NPM",
"NugetPackageCount": "Contagem de pacotes Nuget",
"Module": "Módulos",
"ModuleInfo": "Informações do módulo",
"CreateANpmPackage": "Criar um pacote NPM",
"CreateAModule": "Criar um módulo",
"CreateANugetPackage": "Criar um pacote Nuget",
"AddNew": "Adicionar novo",
"PackageAlreadyExist{0}": "\"{0}\" o pacote já foi adicionado.",
"ClearCache": "Limpar cache",
"SuccessfullyCleared": "Limpo com sucesso",
"Menu:NpmPackages": "Pacotes NPM",
"Menu:Modules": "Módulos",
"Menu:Maintenance": "Manutenção",
"Menu:NugetPackages": "Pacotes Nuget"
}
}

2
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json

@ -8,6 +8,8 @@
"Volo.AbpIo.Domain:010008": "Allowed Developer Count can not be less then current developer count!",
"Volo.AbpIo.Domain:010009": "Allowed Developer Count can not be less then 0!",
"Volo.AbpIo.Domain:010010": "Maximum mac address count is exceeded!",
"Volo.AbpIo.Domain:010011": "Personal license can't have more than 1 developer!",
"Volo.AbpIo.Domain:010012": "License can't be extended one month after license expires!",
"Volo.AbpIo.Domain:020001": "Could not delete this NPM Package because \"{NugetPackages}\" Nuget Packages are dependent to this package.",
"Volo.AbpIo.Domain:020002": "Could not delete this NPM Package because \"{Modules}\" Modules are using this package.",
"Volo.AbpIo.Domain:020003": "Could not delete this NPM Package because \"{Modules}\" Modules are using this package and \"{NugetPackages}\" Nuget Packages are dependent to this package.",

31
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/pt-BR.json

@ -0,0 +1,31 @@
{
"culture": "pt-BR",
"texts": {
"Volo.AbpIo.Domain:010004": "Número máximo de membros atingido!",
"Volo.AbpIo.Domain:010005": "Número máximo de proprietários atingido!",
"Volo.AbpIo.Domain:010006": "Este usuário já é proprietário desta organização!",
"Volo.AbpIo.Domain:010007": "Este usuário já é desenvolvedor desta organização!",
"Volo.AbpIo.Domain:010008": "A contagem permitida de desenvolvedores não pode ser inferior à contagem atual de desenvolvedores!",
"Volo.AbpIo.Domain:010009": "A contagem permitida de desenvolvedores não pode ser inferior a 0!",
"Volo.AbpIo.Domain:010010": "A contagem máxima de endereços mac foi excedida!",
"Volo.AbpIo.Domain:010011": "A licença pessoal não pode ter mais de um desenvolvedor!",
"Volo.AbpIo.Domain:010012": "A licença não pode ser estendida um mês após a expiração da licença!",
"Volo.AbpIo.Domain:020001": "Não foi possível excluir este pacote NPM porque \"{NugetPackages}\" Os pacotes Nuget dependem deste pacote.",
"Volo.AbpIo.Domain:020002": "Não foi possível excluir este pacote NPM porque \"{Modules}\" Módulos estão usando este pacote.",
"Volo.AbpIo.Domain:020003": "Não foi possível excluir este pacote NPM porque \"{Modules}\" Módulos estão usando este pacote e \"{NugetPackages}\" Os pacotes Nuget dependem deste pacote.",
"Volo.AbpIo.Domain:020004": "Não foi possível excluir este pacote Nuget porque \"{Modules}\" Módulos estão usando este pacote.",
"WantToLearn?": "Quer aprender?",
"ReadyToGetStarted?": "Pronto para começar?",
"JoinOurCommunity": "Participe da nossa comunidade",
"GetStartedUpper": "INICIAR",
"ForkMeOnGitHub": "Bifurque-me no GitHub",
"Features": "Recursos",
"GetStarted": "Introdução",
"Documents": "Documentos",
"Community": "Comunidade",
"ContributionGuide": "Guia de contribuição",
"Blog": "Blog",
"Commercial": "Comercial",
"SeeDocuments": "Ver documentos"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json

@ -7,6 +7,8 @@
"Volo.AbpIo.Domain:010007": "Bu kullanıcı zaten bu organizasyonda yazılımcı olarak var!",
"Volo.AbpIo.Domain:010008": "Maksimum izin verilen kullanıcı sayısı mevcut kullanıcı sayısından az olamaz!",
"Volo.AbpIo.Domain:010009": "Maksimum izin verilen kullanıcı sayısı sıfırdan az olamaz!",
"Volo.AbpIo.Domain:010010": "Maksimum mac adresi sayısı geçildi!"
"Volo.AbpIo.Domain:010010": "Maksimum mac adresi sayısı geçildi!",
"Volo.AbpIo.Domain:010011": "Bireysel lisans birden fazla geliştiriciye sahip olamaz!",
"Volo.AbpIo.Domain:010012": "Lisans, lisans süresi bittikten bir ay sonra uzatılamaz!",
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/pt-BR.json

@ -0,0 +1,5 @@
{
"culture": "pt-BR",
"texts": {
}
}

9
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -18,6 +18,13 @@
"Manage": "Manage",
"StartDate": "Start date",
"EndDate": "End date",
"Modules": "Modules"
"Modules": "Modules",
"LicenseExtendMessage": "Your license end date is extended to {0}",
"LicenseUpgradeMessage": "Your license is upgraded to {0}",
"LicenseAddDeveloperMessage": "{0} developers added to your license" ,
"Volo.AbpIo.Commercial:010004": "Can not find the specified user! The user must have already registered.",
"MyOrganizations": "My organizations",
"ApiKey": "API key",
"UserNameNotFound": "There is no user with username {0}"
}
}

30
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json

@ -0,0 +1,30 @@
{
"culture": "pt-BR",
"texts": {
"OrganizationManagement": "Gerenciamento da organização",
"OrganizationList": "Lista de organização",
"Volo.AbpIo.Commercial:010003": "Você não é proprietário desta organização!",
"OrganizationNotFoundMessage": "Nenhuma organização encontrada!",
"DeveloperCount": "Número de desenvolvedores",
"Owners": "Proprietários",
"AddMember": "Adicionar membro",
"AddOwner": "Adicionar proprietário",
"AddDeveloper": "Adicionar desenvolvedor",
"UserName": "Nome de usuário",
"Name": "Nome",
"EmailAddress": "Endereço de email",
"Developers": "Desenvolvedores",
"LicenseType": "Tipo de licença",
"Manage": "Gerenciar",
"StartDate": "Data de início",
"EndDate": "Data final",
"Modules": "Módulos",
"LicenseExtendMessage": "A data de término da sua licença foi estendida para {0}",
"LicenseUpgradeMessage": "Sua licença foi atualizada para {0}",
"LicenseAddDeveloperMessage": "{0} desenvolvedores adicionados à sua licença",
"Volo.AbpIo.Commercial:010004": "Não foi possível encontrar o usuário especificado! O usuário já deve ter se registrado.",
"MyOrganizations": "Minhas organizações",
"ApiKey": "Chave da API",
"UserNameNotFound": "Não há usuário com nome de usuário {0}"
}
}

9
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json

@ -18,6 +18,13 @@
"Manage": "Yönet",
"StartDate": "Başlangıç tarihi",
"EndDate": "bitiş tarihi",
"Modules": "Modüller"
"Modules": "Modüller",
"Volo.AbpIo.Commercial:010004": "Kullanıcı bulunamadı! İlgili kullanıcının daha önceden sisteme kayıt olmuş olması gerekiyor.",
"LicenseExtendMessage": "Lisans bitiş tarihiniz {0} tarihine kadar uzatıldı",
"LicenseUpgradeMessage": "Lisansınız {0} lisansa yükseltildi",
"LicenseAddDeveloperMessage": "Lisansınıza {0} geliştirici eklendi",
"MyOrganizations": "Organizasyonlarım",
"ApiKey": "API anahtarı",
"UserNameNotFound": "{0} kullanıcı adı ile bir kullanıcı yok"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/pt-BR.json

@ -0,0 +1,5 @@
{
"culture": "pt-BR",
"texts": {
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/pt-BR.json

@ -0,0 +1,5 @@
{
"culture": "pt-BR",
"texts": {
}
}

160
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json

@ -0,0 +1,160 @@
{
"culture": "pt-BR",
"texts": {
"GetStarted": "Introdução",
"Create": "Criar",
"NewProject": "Novo projeto",
"DirectDownload": "Download direto",
"ProjectName": "Nome do projeto",
"ProjectType": "Tipo de projeto",
"DatabaseProvider": "Provedor de banco de dados",
"NTier": "N-Tier",
"IncludeUserInterface": "Incluir interface do usuário",
"CreateNow": "Criar agora",
"TheStartupProject": "O projeto de inicialização",
"Tutorial": "Tutorial",
"UsingCLI": "Usando CLI",
"SeeDetails": "Ver detalhes",
"AbpShortDescription": "ABP é uma arquitetura completa e uma forte infraestrutura para criar aplicativos da web modernos! Segue as melhores práticas e convenções para fornecer uma sólida experiência de desenvolvimento.",
"SourceCodeUpper": "CÓDIGO FONTE",
"LatestReleaseLogs": "Últimos registros de lançamento",
"Infrastructure": "Infra-estrutura",
"Architecture": "Arquitetura",
"Modular": "Modular",
"DontRepeatYourself": "Não se repita",
"DeveloperFocused": "Desenvolvedor focado",
"FullStackApplicationInfrastructure": "Infraestrutura de aplicativos full stack.",
"DomainDrivenDesign": "Design Orientado a Domínio",
"DomainDrivenDesignExplanation": "Projetado e desenvolvido com base nos padrões e princípios DDD. Fornece um modelo em camadas para seu aplicativo.",
"Authorization": "Autorização",
"AuthorizationExplanation": "Autorização avançada com usuário, função e sistema de permissão refinado. Criada na biblioteca Microsoft Identity.",
"MultiTenancy": "Múltiplos inquilinos",
"MultiTenancyExplanation": "Aplicativos SaaS facilitados! Multilocação integrada do banco de dados à interface do usuário.",
"CrossCuttingConcerns": "Preocupações transversais",
"CrossCuttingConcernsExplanation": "Infraestrutura completa para autorização, validação, tratamento de exceções, armazenamento em cache, log de auditoria, gerenciamento de transações e assim por diante.",
"BuiltInBundlingMinification": "Pacote & Minificação Integrados",
"BuiltInBundlingMinificationExplanation": "Pare de usar ferramentas externas para empacotamento e minificação. O ABP oferece uma maneira mais simples, dinâmica, poderosa, modular e integrada!",
"VirtualFileSystem": "Sistema de arquivos virtual",
"VirtualFileSystemExplanation": "Incorpore visualizações, scripts, estilos, imagens ... aos pacotes/bibliotecas e reutilize-os em diferentes aplicativos.",
"Theming": "Theming",
"ThemingExplanation": "Use e personalize o tema da interface do usuário padrão baseado em bootstrap-based ou crie o seu próprio.",
"BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers & Dynamic Forms",
"BootstrapTagHelpersDynamicFormsExplanation": "Sistema de tarefas em segundo plano integrado que pode ser integrado ao Hangfire, RabbitMQ ou a qualquer ferramenta que você desejar.", //TODO explanation doesn't match.
"HTTPAPIsDynamicProxies": "APIs HTTP e proxies dinâmicos",
"HTTPAPIsDynamicProxiesExplanation": "Exponha automaticamente os serviços de aplicativo como APIs HTTP do estilo REST e consuma com proxies JavaScript & C # dinâmicos.",
"CompleteArchitectureInfo": "Arquitetura moderna para criar soluções de software sustentáveis.",
"DomainDrivenDesignBasedLayeringModelExplanation": "Ajuda você a implementar uma arquitetura em camadas baseada em DDD e a construir uma base de código sustentável.",
"DomainDrivenDesignBasedLayeringModelExplanationCont": "Fornece modelos de inicialização, abstrações, classes base, serviços, documentação e guias para ajudá-lo a desenvolver seu aplicativo com base nos padrões e princípios DDD.",
"MicroserviceCompatibleModelExplanation": "O framework principal e os módulos de pré-construção foram projetados para a arquitetura de microsserviço.",
"MicroserviceCompatibleModelExplanationCont": "Fornece infraestrutura, integrações, amostras e documentação para implementar soluções de microsserviço mais facilmente, enquanto isso não traga complexidade adicional se você quiser um aplicativo monolítico.",
"ModularInfo": "O ABP fornece um sistema completo de modularidade para permitir o desenvolvimento de módulos de aplicativos reutilizáveis.",
"PreBuiltModulesThemes": "Módulos pré-construídos & Temas",
"PreBuiltModulesThemesExplanation": "Módulos e temas de código aberto e comerciais estão prontos para uso em seu aplicativo de negócios.",
"NuGetNPMPackages": "Pacotes NuGet & NPM",
"NuGetNPMPackagesExplanation": "Distribuído como pacotes NuGet & NPM. Fácil de instalar e atualizar.",
"ExtensibleReplaceable": "Extensível/Substituível",
"ExtensibleReplaceableExplanation": "Todos os serviços e módulos são projetados para extensibilidade. Você pode substituir serviços, páginas, estilos, componentes...",
"CrossCuttingConcernsExplanation2": "Mantenha seu código mais limpo e concentre-se em seu próprio código comercial.",
"CrossCuttingConcernsExplanation3": "Não perca tempo para implementar requisitos de aplicativos comuns repetidamente.",
"AuthenticationAuthorization": "Autenticação & Autorização",
"ExceptionHandling": "Manipulação de exceção",
"Validation": "Validação",
"DatabaseConnection": "Conexão com o Banco de Dados",
"TransactionManagement": "Gerenciamento de transações",
"AuditLogging": "Log de auditoria",
"Caching": "Armazenamento em cache",
"Multitenancy": "Múltiplos inquilinos",
"DataFiltering": "Filtragem de dados",
"ConventionOverConfiguration": "Convenção sobre configuração",
"ConventionOverConfigurationExplanation": "O ABP implementa convenções comuns de aplicativos por padrão com uma configuração mínima ou zero.",
"ConventionOverConfigurationExplanationList1": "Registra automaticamente serviços conhecidos na injeção de dependência.",
"ConventionOverConfigurationExplanationList2": "Expõe os serviços de aplicativos como APIs HTTP, nomeando convenções.",
"ConventionOverConfigurationExplanationList3": "Cria proxies de clientes HTTP dinâmicos para C # e JavaScript.",
"ConventionOverConfigurationExplanationList4": "Fornece repositórios padrão para suas entidades.",
"ConventionOverConfigurationExplanationList5": "Gerencia a unidade de trabalho por solicitação da Web ou método de serviço de aplicativo.",
"ConventionOverConfigurationExplanationList6": "Publica, cria, atualiza e exclui eventos para suas entidades.",
"BaseClasses": "Classes base",
"BaseClassesExplanation": "Classes base pré-criadas para padrões de aplicativos comuns.",
"DeveloperFocusedExplanation": "O ABP é para desenvolvedores.",
"DeveloperFocusedExplanationCont": "Tem como objetivo simplificar o desenvolvimento diário de seu software, sem restringir o trabalho de baixo nível quando necessário.",
"SeeAllFeatures": "Veja todos os recursos",
"CLI_CommandLineInterface": "CLI (Command Line Interface)",
"CLI_CommandLineInterfaceExplanation": "A CLI é automatizada para criar novos projetos e adicionar módulos ao seu aplicativo.",
"StartupTemplates": "Modelos de inicialização",
"StartupTemplatesExplanation": "Vários modelos de inicialização fornecem uma solução totalmente configurada para iniciar rapidamente seu desenvolvimento.",
"BasedOnFamiliarTools": "Baseado em ferramentas familiares",
"BasedOnFamiliarToolsExplanation": "Construído e integrado a ferramentas populares que você já conhece. Baixa curva de aprendizado, fácil adaptação, desenvolvimento confortável.",
"ORMIndependent": "ORM Independente",
"ORMIndependentExplanation": "O framework principal é independente do ORM/banco de dados e pode funcionar com qualquer fonte de dados. Os provedores Entity Framework Core e MongoDB já estão disponíveis.",
"Features": "Recursos",
"ABPCLI": "ABP CLI",
"Modularity": "Modularidade",
"BootstrapTagHelpers": "Bootstrap Tag Helpers",
"DynamicForms": "Formulários dinâmicos",
"BundlingMinification": "Empacotamento e Minificação",
"BackgroundJobs": "Trabalhos em segundo plano",
"DDDInfrastructure": "Infraestrutura DDD",
"DomainDrivenDesignInfrastructure": "Infraestrutura de Design Orientada a Domínio",
"AutoRESTAPIs": "APIs REST automáticas",
"DynamicClientProxies": "Proxies de cliente dinâmicos",
"DistributedEventBus": "Barramento de Eventos Distribuídos",
"DistributedEventBusWithRabbitMQIntegration": "Barramento de Eventos Distribuídos com Integração RabbitMQ",
"TestInfrastructure": "Infraestrutura de Teste",
"AuditLogging": "Log de auditoria",
"AuditLoggingEntityHistories": "Log de auditoria e históricos de entidades",
"ObjectToObjectMapping": "Objeto para Mapeamento de Objetos",
"EmailSMSAbstractions": "Abstrações de E-mail e SMS",
"EmailSMSAbstractionsWithTemplatingSupport": "Abstrações de e-mail e SMS com suporte a modelos",
"Localization": "Localização",
"SettingManagement": "Gerenciamento de configurações",
"ExtensionMethods": "Métodos de extensão",
"ExtensionMethodsHelpers": "Métodos de extensão & Helpers",
"AspectOrientedProgramming": "Programação Orientada a Aspectos",
"DependencyInjection": "Injeção de dependência",
"DependencyInjectionByConventions": "Injeção de dependência por convenções",
"ABPCLIExplanation": "O ABP CLI (Command Line Interface) é uma ferramenta de linha de comando para executar algumas operações comuns em soluções baseadas em ABP.",
"ModularityExplanation": "O ABP fornece uma infraestrutura completa para criar seus próprios módulos de aplicativos, que podem ter entidades, serviços, integração de banco de dados, APIs, componentes de interface do usuário e assim por diante ...", //TODO: strong "your own application modules",-
"MultiTenancyExplanation": "ABP framework não apenas suporta o desenvolvimento de aplicativos com vários inquilinos, mas também faz com que seu código desconheça a multilocação.",
"MultiTenancyExplanation2": "Pode determinar automaticamente o inquilino atual, isolar os dados de inquilinos diferentes um do outro.",
"MultiTenancyExplanation3": "Suporta abordagens de banco de dados único, banco de dados por inquilino e híbrido.",
"MultiTenancyExplanation4": "Você se concentra no seu código comercial e deixa o framework lidar com a multilocação em seu nome.",
"BootstrapTagHelpersExplanation": "Em vez de escrever manualmente os detalhes repetidos dos componentes do bootstrap, use os tag helpers da ABP para simplificá-lo e tirar proveito do intellisense. Você pode definitivamente usar o Bootstrap sempre que precisar.",
"DynamicFormsExplanation": "Formulário dinâmico e entrada de tag helpers pode criar o formulário completo a partir de uma classe C# como modelo.",
"AuthenticationAuthorizationExplanation": "Opções avançadas de autenticação e autorização integradas ao ASP.NET Core Identity & IdentityServer4. Fornece um sistema de permissões extensível e detalhado.",
"CrossCuttingConcernsExplanation": "Não se repita para implementar todas essas coisas comuns repetidamente. Concentre-se no seu código comercial e permita que a ABP os automatize por convenções.",
"DatabaseConnectionTransactionManagement": "Gerenciamento de conexão e transação de banco de dados",
"CorrelationIdTracking": "Rastreamento de ID de correlação",
"BundlingMinificationExplanation": "A ABP oferece um sistema de empacotamento e minificação simples, dinâmico, poderoso, modular e embutido.",
"VirtualFileSystemnExplanation": "O Sistema de Arquivos Virtual possibilita gerenciar arquivos que não existem fisicamente no sistema de arquivos (disco). É usado principalmente para incorporar arquivos (js, css, image, cshtml ...) em assemblies e usar como arquivos físicos em tempo de execução.",
"ThemingExplanation": "O sistema Theming permite o desenvolvimento independente do tema do aplicativo e dos módulos, definindo um conjunto de bibliotecas e layouts básicos comuns, com base na estrutura mais recente do Bootstrap.",
"DomainDrivenDesignInfrastructureExplanation": "Uma infraestrutura completa para criar aplicativos em camadas com base nos padrões e princípios de Design Orientado a Domínio;",
"Specification": "Especificação",
"Repository": "Repositório",
"DomainService": "Serviço de Domínio",
"ValueObject": "Value Object",
"ApplicationService": "Serviço de Aplicativo",
"DataTransferObject": "Objeto de transferência de dados",
"AggregateRootEntity": "Raiz agregada, entidade",
"AutoRESTAPIsExplanation": "O ABP pode configurar automaticamente seus serviços de aplicativo como controladores de API por convenção.",
"DynamicClientProxiesExplanation": "Consumir facilmente suas APIs de JavaScript e C # clientes.",
"DistributedEventBusWithRabbitMQIntegrationExplanation": "Publique e consuma facilmente eventos distribuídos usando o Barramento de Eventos Distribuídos interno com a integração RabbitMQ disponível.",
"TestInfrastructureExplanation": "A estrutura foi desenvolvida para testes de unidade e integração. Fornece classes básicas para facilitar. Os modelos de inicialização são pré-configurados para teste.",
"AuditLoggingEntityHistoriesExplanation": "Registro de auditoria interno para aplicativos críticos para os negócios. Solicitação, serviço, log de auditoria no nível do método e histórico de entidades com detalhes no nível da propriedade.",
"EmailSMSAbstractionsWithTemplatingSupportExplanation": "As abstrações IEmailSender e ISmsSender dissociam sua lógica de aplicativo da infraestrutura. O sistema avançado de modelo de email permite criar e localizar modelos de email e usá-lo facilmente sempre que necessário.",
"LocalizationExplanation": "O sistema de localização permite criar recursos em arquivos JSON simples e usá-los para localizar sua interface do usuário. Ele suporta cenários avançados como herança, extensões e integração de JavaScript, enquanto é totalmente compatível com o sistema de localização do AspNet Core.",
"SettingManagementExplanation": "Defina as configurações do seu aplicativo e obtenha valores no tempo de execução com base na configuração atual, inquilino e usuário.",
"ExtensionMethodsHelpersExplanation": "Não se repita, mesmo em partes triviais do código. Extensões e helpers para tipos padrão tornam seu código muito mais limpo e fácil de escrever.",
"AspectOrientedProgrammingExplanation": "Fornece uma infraestrutura confortável para criar proxies dinâmicos e implementar a Programação Orientada a Aspectos. Intercepte qualquer classe e execute seu código antes e depois de cada execução de método.",
"DependencyInjectionByConventionsExplanation": "Não há necessidade de registrar suas classes na injeção de dependência manualmente. Registra automaticamente tipos de serviço comuns por convenção. Para outros tipos de serviços, você pode usar interfaces e atributos para facilitar e colocar no local.",
"DataFilteringExplanation": "Defina e use filtros de dados que serão aplicados automaticamente quando você consultar entidades do banco de dados. Os filtros Soft Delete e MultiTenant são fornecidos imediatamente quando você implementa interfaces simples.",
"PublishEvents": "Publicar eventos",
"HandleEvents": "Manipular Eventos",
"AndMore": "e mais...",
"Code": "Código",
"Result": "Resultado",
"SeeTheDocumentForMoreInformation": "Consulte o <a href=\"{1}\">{0} documento</a> para obter mais informações",
"IndexPageHeroSection": "<span class=\"first-line shine\"><strong>código aberto</strong></span><span class=\"second-line text-uppercase\">Aplicativo da Web<br />Framework </span><span class=\"third-line shine2\"><strong>para o ASP.NET Core</strong></span>",
"UiFramework": "UI Framework",
"EmailAddress": "Endereço de email"
}
}

2
common.props

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>0.19.0</Version>
<Version>0.22.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io</PackageProjectUrl>

10
common.test.props

@ -0,0 +1,10 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
</PropertyGroup>
</Project>

35
docs/cs/Best-Practices/PostgreSQL-Integration.md

@ -0,0 +1,35 @@
## Entity Framework Core PostgreSQL integrace
> Podívejte se na [Entity Framework Core integrační dokument](../Entity-Framework-Core.md) pro základy integrace EF Core.
### Aktualizace projektu EntityFrameworkCore
- V projektu `Acme.BookStore.EntityFrameworkCore` nahraďte balík `Volo.Abp.EntityFrameworkCore.SqlServer` za `Volo.Abp.EntityFrameworkCore.PostgreSql`
- Aktualizace pro použití PostgreSQL v `BookStoreEntityFrameworkCoreModule`
- Nahraďte `AbpEntityFrameworkCoreSqlServerModule` za `AbpEntityFrameworkCorePostgreSqlModule`
- Nahraďte `options.UseSqlServer()` za `options.UsePostgreSql()`
- V jiných projektech aktualizujte PostgreSQL connection string v nezbytných `appsettings.json` souborech
#### Odstranění stávajících migrací
Smažte všechny stavající migrační soubory (včetně `DbContextModelSnapshot`)
![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png)
#### Znovu vygenerujte počáteční migraci & aktualizujte databázi
Nastavte správný spouštěcí projekt (obvykle web projekt),
Otevřete **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), zvolte `Acme.BookStore.EntityFrameworkCore.DbMigrations` jako **Default project** a proveďte následující příkaz:
Proveďte příkaz `Add-Migration`:
````
PM> Add-Migration Initial
````
Poté proveďte příkaz `Update-Database` k aktualizaci schématu databáze:
````
PM> Update-Database
````
![postgresql-update-database](images/postgresql-update-database.png)

BIN
docs/cs/Best-Practices/images/postgresql-delete-initial-migrations.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
docs/cs/Best-Practices/images/postgresql-update-database.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

61
docs/cs/Dapper.md

@ -0,0 +1,61 @@
# Dapper integrace
Jelikož myšlenka Dapper je taková, že sql příkaz má přednost, tak hlavně poskytuje metody rozšíření pro `IDbConnection` rozhraní.
Abp nezapouzdřuje přílíš mnoho funkcí pro Dapper. Abp Dapper poskytuje základní třídu `DapperRepository<TDbContext>` založenou na Abp EntityFrameworkCore, který poskytuje vlastnosti `IDbConnection` a `IDbTransaction` vyžadované v Dapper.
Tyto dvě vlastnosti fungují dobře s [jednotkou práce](Unit-Of-Work.md).
## Instalace
Nainstalujte a nakonfigurujte EF Core podle [EF Core integrační dokumentace](Entity-Framework-Core.md).
`Volo.Abp.Dapper` je hlavní NuGet balík pro Dapper integraci. Nainstalujte jej proto do vašeho projektu (pro strukturovanou aplikaci do datové/infrastrukturní vrstvy):
```shell
Install-Package Volo.Abp.Dapper
```
Poté přidejte závislost na `AbpDapperModule` modulu (atribut `DependsOn`) do Vašeho [modulu](Module-Development-Basics.md):
````C#
using Volo.Abp.Dapper;
using Volo.Abp.Modularity;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpDapperModule))]
public class MyModule : AbpModule
{
//...
}
}
````
## Implementace Dapper repozitáře
Následující kód implementuje repozitář `Person`, který vyžaduje `DbContext` z EF Core (MyAppDbContext). Můžete vložit `PersonDapperRepository` k volání jeho metod.
`DbConnection` a `DbTransaction` jsou ze základní třídy `DapperRepository`.
```C#
public class PersonDapperRepository : DapperRepository<MyAppDbContext>, ITransientDependency
{
public PersonDapperRepository(IDbContextProvider<MyAppDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public virtual async Task<List<string>> GetAllPersonNames()
{
return (await DbConnection.QueryAsync<string>("select Name from People", transaction: DbTransaction))
.ToList();
}
public virtual async Task<int> UpdatePersonNames(string name)
{
return await DbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name },
DbTransaction);
}
}
```

126
docs/cs/Getting-Started-Angular-Template.md

@ -0,0 +1,126 @@
## Začínáme s Angular aplikační šablonou
Tento tutoriál vysvětluje, jak vytvořit novou Angular aplikaci pomocí spouštěcí šablony, jak ji nakonfigurovat a spustit.
### Tvorba nového projektu
Tento tutorial používá k vytvoření nového projektu **ABP CLI**. Podívejte se na stránku [začínáme](https://abp.io/get-started) pro více možností.
Pokud jste tak dosud neučinili, nainstalujte ABP CLI pomocí okna příkazového řádku:
````bash
dotnet tool install -g Volo.Abp.Cli
````
Použíjte příkaz `abp new` v prázdné složce k vytvoření Vašeho projektu:
````bash
abp new Acme.BookStore -u angular
````
> Můžete použít různé úrovně jmenných prostorů; např. BookStore, Acme.BookStore nebo Acme.Retail.BookStore.
`-u angular` volba specifikuje Angular jako UI framework. Výchozí poskytovatel databáze je EF Core. Podívejte se na [CLI dokumentaci](CLI.md) pro všechny dostupné možnosti.
#### Předběžné požadavky
Vytvořené řešení vyžaduje;
* [Visual Studio 2017 (v15.9.0+)](https://visualstudio.microsoft.com/tr/downloads/)
* [.NET Core 2.2+](https://www.microsoft.com/net/download/dotnet-core/)
* [Node v10.16+](https://nodejs.org)
* [Yarn v1.17+](https://yarnpkg.com/)
### Struktura řešení
Otevřete řešení ve **Visual Studio**:
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-for-spa.png)
Řešení má vrstvenou strukturu (založenou na [domain driven designu](Domain-Driven-Design.md)) a obsahuje projekty testů jednotek a integrace správně nakonfigurované pro práci s **EF Core** & **SQLite in-memory** databází.
> Podívejte se na [dokument šablony aplikace](Startup-Templates/Application.md) k detailnímu pochopení struktury řešení.
### Databázový connection string
Zkontrolujte **connection string** v souboru `appsettings.json` u projektu `.HttpApi.Host`:
````json
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
}
}
````
Řešení je nakonfigurováno pro použití **Entity Framework Core** s **MS SQL Server**. EF Core podporuje [různé](https://docs.microsoft.com/en-us/ef/core/providers/) poskytovatele databáze, takže pokud chcete můžete použít jiný DBMS. V případě potřeby změňte connection string.
### Tvorba databáze & aplikace migrací databáze
K vytvoření databáze máte dvě možnosti.
#### Použití aplikace DbMigrator
Řešení obsahuje konzolovou aplikaci (v tomto příkladu nazvanou `Acme.BookStore.DbMigrator`), která dokáže vytvořit databázi, aplikovat migrace a vložit počáteční data. Ta je užitečná jak pro vývojové tak pro produkční prostředí.
> `.DbMigrator` má vlastní `appsettings.json`. Pokud jste změnili connection string výše, měli byste změnit i tento.
Klikněte pravým na projekt `.DbMigrator` zvolte **Set as StartUp Project**:
![set-as-startup-project](images/set-as-startup-project.png)
Zmáčkněte F5 (nebo Ctrl+F5) ke spuštění aplikace. Výstup by měl být podobný vyobrazení níže:
![set-as-startup-project](images/db-migrator-app.png)
#### Použití příkazu EF Core Update-Database
Ef Core máš příkaz `Update-Database`, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. Klikněte pravým na projekt `.Web` a zvolte **Set as StartUp Project**:
![set-as-startup-project](images/set-as-startup-project.png)
Otevřete **Package Manager Console**, zvolte `.EntityFrameworkCore.DbMigrations` jako **Default Project** a proveďte příkaz `Update-Database`:
![pcm-update-database](images/pcm-update-database-v2.png)
Tímto vytvoříte novou databáze podle nakonfigurovaného connection string.
> Je doporučeno užití nástroje `.DbMigrator`, protože zároveň vloží i počáteční data ke správnému běhu webové aplikace.
### Spuštění aplikace
#### Spuštění API Host (na straně serveru)
Ujistěte se že je projekt `.HttpApi.Host` nastaven jako startovací a spusťte aplikaci což otevře Swagger UI:
![bookstore-homepage](images/bookstore-swagger-ui-host.png)
Tady můžete vidět API aplikace a zároveň je i otestovat. Získejte [více informací](https://swagger.io/tools/swagger-ui/) o Swagger UI.
##### Autorizace pro Swagger UI
Vetšina API aplikace vyžaduje autentizaci & autorizaci. Pokud chcete otestovat autorizované API, manuálně přejděte na stránku `/Account/Login`, vložte `admin` jako uživatelské jméno a `1q2w3E*` jako heslo k příhlášení do aplikace. Poté budete moci provádět autorizované požadavky API.
#### Spuštění Angular aplikace (na straně klienta)
Přejděte do složky `angular`, otevřete terminál příkazového řádku, proveďte příkaz `yarn` (doporučujeme používat správce balíků [yarn](https://yarnpkg.com), npm install bude v mnoha případech také fungovat):
````bash
yarn
````
Jakmile jsou načteny všechny node moduly, proveďte příkaz `yarn start` nebo `npm start`:
````bash
yarn start
````
Otevřete Váš oblíbený prohlížeč a přejděte na adresu `localhost:4200`. Počáteční uživatelské jméno je `admin` a heslo `1q2w3E*`.
Startovací šablona obsahuje moduly **správa identit** a **správa tenantů**. Jakmile se přihlásíte, zprístupní se administrační menu kde můžete spravovat **tenanty**, **role**, **uživatele** a jejich **oprávnění**.
> Doporučujeme [Visual Studio Code](https://code.visualstudio.com/) jako editor pro Angular projekt, ale klidně použijte Váš oblíbený editor.
### Co dále?
* [Tutoriál vývoje aplikace](Tutorials/Angular/Part-I.md)

14
docs/cs/docs-nav.json

@ -202,7 +202,7 @@
"items": [
{
"text": "API",
"items": [
"items": [
{
"text": "Automatické API řadiče",
"path": "AspNetCore/Auto-API-Controllers.md"
@ -245,11 +245,21 @@
"items": [
{
"text": "Entity Framework Core integrace",
"path": "Entity-Framework-Core.md"
"path": "Entity-Framework-Core.md",
"items": [
{
"text": "PostgreSQL integrace",
"path": "Best-Practices/PostgreSQL-Integration.md"
}
]
},
{
"text": "MongoDB integrace",
"path": "MongoDB.md"
},
{
"text": "Dapper integrace",
"path": "Dapper.md"
}
]
},

5
docs/docs-langs.json

@ -4,6 +4,11 @@
"DisplayName" : "English",
"Code" : "en",
"IsDefault": true
},
{
"DisplayName" : "Português",
"Code" : "pt-BR",
"IsDefault": false
},
{
"DisplayName" : "简体中文",

3
docs/en/AspNetCore/JavaScript-API/Auth.md

@ -0,0 +1,3 @@
# abp.auth JavaScript API
TODO

24
docs/en/AspNetCore/JavaScript-API/Index.md

@ -0,0 +1,24 @@
# JavaScript API
ABP provides some JavaScript APIs for ASP.NET Core MVC / Razor Pages applications. They can be used to perform some common application requirements in the client side.
## APIs
* abp.ajax
* [abp.auth](Auth.md)
* abp.currentUser
* abp.dom
* abp.event
* abp.features
* abp.localization
* abp.log
* abp.ModalManager
* abp.notify
* abp.security
* abp.setting
* abp.ui
* abp.utils
* abp.ResourceLoader
* abp.WidgetManager
* Other APIs

370
docs/en/Authorization.md

@ -1,3 +1,369 @@
## Authorization
# Authorization
TODO
Authorization is used to check if a user is allowed to perform some specific operations in the application.
ABP extends [ASP.NET Core Authorization](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction) by adding **permissions** as auto [policies](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies) and allowing authorization system to be usable in the **[application services](Application-Services.md)** too.
So, all the ASP.NET Core authorization features and the documentation are valid in an ABP based application. This document focuses on the features that added on top of ASP.NET Core authorization features.
## Authorize Attribute
ASP.NET Core defines the [**Authorize**](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/simple) attribute that can be used for an action, a controller or a page. ABP allows you to use the same attribute for an [application service](Application-Services.md) too.
Example:
````csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Services;
namespace Acme.BookStore
{
[Authorize]
public class AuthorAppService : ApplicationService, IAuthorAppService
{
public Task<List<AuthorDto>> GetListAsync()
{
...
}
[AllowAnonymous]
public Task<AuthorDto> GetAsync(Guid id)
{
...
}
[Authorize("BookStore_Author_Create")]
public Task CreateAsync(CreateAuthorDto input)
{
...
}
}
}
````
* `Authorize` attribute forces the user to login into the application in order to use the `AuthorAppService` methods. So, `GetListAsync` method is only available to the authenticated users.
* `AllowAnonymous` suppresses the authentication. So, `GetAsync` method is available to everyone including unauthorized users.
* `[Authorize("BookStore_Author_Create")]` defines a policy (see [policy based authorization](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies)) that is checked to authorize the current user.
"BookStore_Author_Create" is an arbitrary policy name. If you declare an attribute like that, ASP.NET Core authorization system expects a policy to be defined before.
You can, of course, implement your policies as stated in the ASP.NET Core documentation. But for simple true/false conditions like a policy was granted to a user or not, ABP defines the permission system which will be explained in the next section.
## Permission System
A permission is a simple policy that is granted or prohibited for a particular user, role or client.
### Defining Permissions
To define permissions, create a class inheriting from the `PermissionDefinitionProvider` as shown below:
````csharp
using Volo.Abp.Authorization.Permissions;
namespace Acme.BookStore.Permissions
{
public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var myGroup = context.AddGroup("BookStore");
myGroup.AddPermission("BookStore_Author_Create");
}
}
}
````
> ABP automatically discovers this class. No additional configuration required!
In the `Define` method, you first need to add a **permission group** or get an existing group then add **permissions** to this group.
When you define a permission, it becomes usable in the ASP.NET Core authorization system as a **policy** name. It also becomes visible in the UI. See permissions dialog for a role:
![authorization-new-permission-ui](images/authorization-new-permission-ui.png)
* The "BookStore" group is shown as a new tab on the left side.
* "BookStore_Author_Create" on the right side is the permission name. You can grant or prohibit it for the role.
When you save the dialog, it is saved to the database and used in the authorization system.
> The screen above is available when you have installed the identity module, which is basically used for user and role management. Startup templates come with the identity module pre-installed.
#### Localizing the Permission Name
"BookStore_Author_Create" is not a good permission name for the UI. Fortunately, `AddPermission` and `AddGroup` methods can take `LocalizableString` as second parameters:
````csharp
var myGroup = context.AddGroup(
"BookStore",
LocalizableString.Create<BookStoreResource>("BookStore")
);
myGroup.AddPermission(
"BookStore_Author_Create",
LocalizableString.Create<BookStoreResource>("Permission:BookStore_Author_Create")
);
````
Then you can define texts for "BookStore" and "Permission:BookStore_Author_Create" keys in the localization file:
````json
"BookStore": "Book Store",
"Permission:BookStore_Author_Create": "Creating a new author"
````
> For more information, see the [localization document](Localization.md) on the localization system.
The localized UI will be as seen below:
![authorization-new-permission-ui-localized](images/authorization-new-permission-ui-localized.png)
#### Multi-Tenancy
ABP supports [multi-tenancy](Multi-Tenancy.md) as a first class citizen. You can define multi-tenancy side option while defining a new permission. It gets one of the three values defined below:
* **Host**: The permission is available only for the host side.
* **Tenant**: The permission is available only for the tenant side.
* **Both** (default): The permission is available both for tenant and host sides.
> If your application is not multi-tenant, you can ignore this option.
To set the multi-tenancy side option, pass to the third parameter of the `AddPermission` method:
````csharp
myGroup.AddPermission(
"BookStore_Author_Create",
LocalizableString.Create<BookStoreResource>("Permission:BookStore_Author_Create"),
multiTenancySide: MultiTenancySides.Tenant //set multi-tenancy side!
);
````
#### Child Permissions
A permission may have child permissions. It is especially useful when you want to create a hierarchical permission tree where a permission may have additional sub permissions which are available only if the parent permission has been granted.
Example definition:
````csharp
var authorManagement = myGroup.AddPermission("Author_Management");
authorManagement.AddChild("Author_Management_Create_Books");
authorManagement.AddChild("Author_Management_Edit_Books");
authorManagement.AddChild("Author_Management_Delete_Books");
````
The result on the UI is shown below (you probably want to localize permissions for your application):
![authorization-new-permission-ui-hierarcy](images/authorization-new-permission-ui-hierarcy.png)
For the example code, it is assumed that a role/user with "Author_Management" permission granted may have additional permissions. Then a typical application service that checks permissions can be defined as shown below:
````csharp
[Authorize("Author_Management")]
public class AuthorAppService : ApplicationService, IAuthorAppService
{
public Task<List<AuthorDto>> GetListAsync()
{
...
}
public Task<AuthorDto> GetAsync(Guid id)
{
...
}
[Authorize("Author_Management_Create_Books")]
public Task CreateAsync(CreateAuthorDto input)
{
...
}
[Authorize("Author_Management_Edit_Books")]
public Task UpdateAsync(CreateAuthorDto input)
{
...
}
[Authorize("Author_Management_Delete_Books")]
public Task DeleteAsync(CreateAuthorDto input)
{
...
}
}
````
* `GetListAsync` and `GetAsync` will be available to users if they have `Author_Management` permission is granted.
* Other methods require additional permissions.
### Overriding a Permission by a Custom Policy
If you define and register a policy to the ASP.NET Core authorization system with the same name of a permission, your policy will override the existing permission. This is a powerful way to extend the authorization for a pre-built module that you are using in your application.
See [policy based authorization](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies) document to learn how to define a custom policy.
## IAuthorizationService
ASP.NET Core provides the `IAuthorizationService` that can be used to check for authorization. Once you inject, you can use it in your code to conditionally control the authorization.
Example:
````csharp
public async Task CreateAsync(CreateAuthorDto input)
{
var result = await AuthorizationService
.AuthorizeAsync("Author_Management_Create_Books");
if (result.Succeeded == false)
{
//throw exception
throw new AbpAuthorizationException("...");
}
//continue to the normal flow...
}
````
> `AuthorizationService` is available as a property when you derive from ABP's `ApplicationService` base class. Since it is widely used in application services, `ApplicationService` pre-injects it for you. Otherwise, you can directly [inject](Dependency-Injection.md) it into your class.
Since this is a typical code block, ABP provides extension methods to simplify it.
Example:
````csharp
public async Task CreateAsync(CreateAuthorDto input)
{
await AuthorizationService.CheckAsync("Author_Management_Create_Books");
//continue to the normal flow...
}
````
`CheckAsync` extension method throws `AbpAuthorizationException` if the current user/client is not granted for the given permission. There is also `IsGrantedAsync` extension method that returns `true` or `false`.
`IAuthorizationService` has some overloads for the `AuthorizeAsync` method. These are explained in the [ASP.NET Core authorization documentation](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction).
> Tip: Prefer to use the `Authorize` attribute wherever possible, since it is declarative & simple. Use `IAuthorizationService` if you need to conditionally check a permission and run a business code based on the permission check.
### Check a Permission in JavaScript
You may need to check a policy/permission on the client side. For ASP.NET Core MVC / Razor Pages applications, you can use the `abp.auth` API. Example:
````js
abp.auth.isGranted('MyPermissionName');
````
See [abp.auth](AspNetCore/JavaScript-API/Auth.md) API documentation for details.
## Permission Management
Permission management is normally done by an admin user using the permission management modal:
![authorization-new-permission-ui-localized](images/authorization-new-permission-ui-localized.png)
If you need to manage permissions by code, inject the `IPermissionManager` and use as shown below:
````csharp
public class MyService : ITransientDependency
{
private readonly IPermissionManager _permissionManager;
public MyService(IPermissionManager permissionManager)
{
_permissionManager = permissionManager;
}
public async Task GrantPermissionForUserAsync(Guid userId, string permissionName)
{
await _permissionManager.SetForUserAsync(userId, permissionName, true);
}
public async Task ProhibitPermissionForUserAsync(Guid userId, string permissionName)
{
await _permissionManager.SetForUserAsync(userId, permissionName, false);
}
}
````
`SetForUserAsync` sets the value (true/false) for a permission of a user. There are more extension methods like `SetForRoleAsync` and `SetForClientAsync`.
`IPermissionManager` is defined by the permission management module. See the [permission management module documentation](Modules/Permission-Management.md) for more information.
## Advanced Topics
### Permission Value Providers
Permission checking system is extensible. Any class derived from `PermissionValueProvider` (or implements `IPermissionValueProvider`) can contribute to the permission check. There are three pre-defined value providers:
* `UserPermissionValueProvider` checks if the current user is granted for the given permission. It gets user id from the current claims. User claim name is defined with the `AbpClaimTypes.UserId` static property.
* `RolePermissionValueProvider` checks if any of the roles of the current user is granted for the given permission. It gets role names from the current claims. Role claims name is defined with the `AbpClaimTypes.Role` static property.
* `ClientPermissionValueProvider` checks if the current client is granted for the given permission. This is especially useful on a machine to machine interaction where there is no current user. It gets the client id from the current claims. Client claim name is defined with the `AbpClaimTypes.ClientId` static property.
You can extend the permission checking system by defining your own permission value provider.
Example:
````csharp
public class SystemAdminPermissionValueProvider : PermissionValueProvider
{
public SystemAdminPermissionValueProvider(IPermissionStore permissionStore)
: base(permissionStore)
{
}
public override string Name => "SystemAdmin";
public override async Task<PermissionGrantResult>
CheckAsync(PermissionValueCheckContext context)
{
if (context.Principal?.FindFirst("User_Type")?.Value == "SystemAdmin")
{
return PermissionGrantResult.Granted;
}
return PermissionGrantResult.Undefined;
}
}
````
This provider allows for all permissions to a user with a `User_Type` claim that has `SystemAdmin` value. It is common to use current claims and `IPermissionStore` in a permission value provider.
A permission value provider should return one of the following values from the `CheckAsync` method:
* `PermissionGrantResult.Granted` is returned to grant the user for the permission. If any of the providers return `Granted`, the result will be `Granted`, if no other provider returns `Prohibited`.
* `PermissionGrantResult.Prohibited` is returned to prohibit the user for the permission. If any of the providers return `Prohibited`, the result will always be `Prohibited`. Doesn't matter what other providers return.
* `PermissionGrantResult.Undefined` is returned if this value provider could not decide about the permission value. Return this to let other providers check the permission.
Once a provider is defined, it should be added to the `PermissionOptions` as shown below:
````csharp
Configure<PermissionOptions>(options =>
{
options.ValueProviders.Add<SystemAdminPermissionValueProvider>();
});
````
### Permission Store
`IPermissionStore` is the only interface that needs to be implemented to read the value of permissions from a persistence source, generally a database system. Permission management module implements it. See the [permission management module documentation](Modules/Permission-Management.md) for more information
### AlwaysAllowAuthorizationService
`AlwaysAllowAuthorizationService` is a class that is used to bypass the authorization service. It is generally used in integration tests where you may want to disable the authorization system.
Use `IServiceCollection.AddAlwaysAllowAuthorization()` extension method to register the `AlwaysAllowAuthorizationService` to the [dependency injection](Dependency-Injection.md) system:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAlwaysAllowAuthorization();
}
````
This is already done for the startup template integration tests.
## See Also
* [Permission Management Module](Modules/Permission-Management.md)
* [ASP.NET Core MVC / Razor Pages JavaScript Auth API](AspNetCore/JavaScript-API/Auth.md)

21
docs/en/Blog-Posts/2019-09-25 v0_21_Release/Post.md

@ -0,0 +1,21 @@
# ABP v0.21 Has Been Released based on the ASP.NET Core 3.0
Just one hour after Microsoft released it, ABP v0.21 [has been released](https://twitter.com/abpframework/status/1176185493119258624) based on the ASP.NET Core 3.0.
v0.21 has no new feature. It just upgrades to the stable ASP.NET Core 3.0. Check [v0.20 release notes](https://github.com/abpframework/abp/releases/tag/0.20.0) for new features, enhancements and bug fixes.
## About v1.0
ABP framework is getting closer to v1.0. We intent to release it in the middle of this October. In this time, we will test and document more.
## .NET Conf 2019
Microsoft has lunched ASP.NET Core 3.0 in the .NET Conf 2019, a 3-days virtual conference. ABP's lead developer [Halil ibrahim Kalkan](https://twitter.com/hibrahimkalkan) has also talked in the conference to introduce the ABP framework. It was great to be a part of this important event.
## Techorama Netherlands 2019
[Techorama NL](https://techorama.nl/) is one of the biggest conferences in Europe. This year, Volosoft is a sponsor of the conference and will have a booth to talk to software developers about the ABP framework and software development. Our booth wall will look like shown below:
![volosoft-booth](volosoft-booth.png)
If you are in the conference, come to out booth to talk about the ABP framework. We will also have nice swags for you :)

BIN
docs/en/Blog-Posts/2019-09-25 v0_21_Release/volosoft-booth.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

82
docs/en/Caching.md

@ -1,3 +1,85 @@
# Caching
ABP framework extends ASP.NET Core's distributed caching system.
## IDistributedCache Interface
ASP.NET Core defines the `IDistributedCache` interface to get/set cache values. But it has some difficulties:
* It works with **byte arrays** rather than .NET objects. So, you need to **serialize/deserialize** the objects you need to cache.
* It provides a **single key pool** for all cache items, so;
* You need to care about the keys to distinguish **different type of objects**.
* You need to care about the cache items of **different tenants** (see [multi-tenancy](Multi-Tenancy.md)).
> `IDistributedCache` is defined in the `Microsoft.Extensions.Caching.Abstractions` package. That means it is not only usable for ASP.NET Core applications, but also available to **any type of applications**.
> Default implementation of the `IDistributedCache` interface is the `MemoryDistributedCache` which works **in-memory**. See [ASP.NET Core's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) to see how to switch to **Redis** or another cache provider.
See [ASP.NET Core's distributed caching document](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) for more information.
## IDistributedCache<TCacheItem> Interface
ABP framework defines the generic `IDistributedCache<TCacheItem>` interface in the [Volo.Abp.Caching](https://www.nuget.org/packages/Volo.Abp.Caching/) package. `TCacheItem` is the type of the object stored in the cache.
`IDistributedCache<TCacheItem>` solves the difficulties explained above;
* It internally **serializes/deserializes** the cached objects. Uses **JSON** serialization by default, but can be overridden by replacing the `IDistributedCacheSerializer` service in the [dependency injection](Dependency-Injection.md) system.
* It automatically adds a **cache name** prefix to the cache keys based on the object type stored in the cache. Default cache name is the full name of the cache item class (`CacheItem` postfix is removed if your cache item class ends with it). You can use the `CacheName` attribute on the cache item class to set the cache name.
* It automatically adds the **current tenant id** to the cache key to distinguish cache items for different tenants (only works if your application is [multi-tenant](Multi-Tenancy.md)). Define `IgnoreMultiTenancy` attribute on the cache item class to disable this if you want to share the cached objects among all tenants in a multi-tenant application.
* Allows to define a **global cache key prefix** per application, so different applications can use their isolated key pools in a shared distributed cache source.
### Usage
An example class to store an item in the cache:
````csharp
public class BookCacheItem
{
public string Name { get; set; }
public float Price { get; set; }
}
````
You can inject and use the `IDistributedCache<BookCacheItem>` service to get/set `BookCacheItem` objects.
Example usage:
````csharp
public class BookService : ITransientDependency
{
private readonly IDistributedCache<BookCacheItem> _cache;
public BookService(IDistributedCache<BookCacheItem> cache)
{
_cache = cache;
}
public async Task<BookCacheItem> GetAsync(Guid bookId)
{
return await _cache.GetOrAddAsync(
bookId.ToString(), //Cache key
async () => await GetBookFromDatabaseAsync(bookId),
() => new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddHours(1)
}
);
}
private Task<BookCacheItem> GetBookFromDatabaseAsync(Guid bookId)
{
//TODO: get from database
}
}
````
* This sample service uses the `GetOrAddAsync()` method to get a book item from the cache.
* If the book was not found in the cache, it calls the factory method (`GetBookFromDatabaseAsync` in this case) to retrieve the book item from the original source.
* `GetOrAddAsync` optionally gets a `DistributedCacheEntryOptions` which can be used to set the lifetime of the cached item.
Other methods of the `IDistributedCache<BookCacheItem>` are same as ASP.NET Core's `IDistributedCache` interface, so you can refer [it's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed).
### DistributedCacheOptions
TODO

4
docs/en/Getting-Started-Angular-Template.md

@ -85,13 +85,13 @@ Open the **Package Manager Console**, select `.EntityFrameworkCore.DbMigrations`
This will create a new database based on the configured connection string.
> Using the `.Migrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application.
> Using the `.DbMigrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application.
### Running the Application
#### Run the API Host (Server Side)
Ensure that the `.HttpApi.Host` project is the startup project and un the application which will open a Swagger UI:
Ensure that the `.HttpApi.Host` project is the startup project and run the application which will open a Swagger UI:
![bookstore-homepage](images/bookstore-swagger-ui-host.png)

4
docs/en/Modules/Index.md

@ -15,7 +15,7 @@ There are some **free and open source** application modules developed and mainta
* **Audit Logging**: Used to persist audit logs to a database.
* **Background Jobs**: Used to persist background jobs when using default background job manager.
* **Blogging**: Used to create fancy blogs. ABP's [own blog](https://abp.io/blog/abp/) already using this module.
* [**Docs**](Docs.md): Used to create technical documentation pages. ABP's [own documentation](https://abp.io/documents/) already using this module.
* [**Docs**](Docs.md): Used to create technical documentation pages. ABP's [own documentation](https://docs.abp.io) already using this module.
* **Identity**: Used to manage roles, users and their permissions.
* **Identity Server**: Integrates to IdentityServer4.
* **Permission Management**: Used to persist permissions.
@ -23,4 +23,4 @@ There are some **free and open source** application modules developed and mainta
* **Tenant Management**: Used to manage tenants for a [multi-tenant](../Multi-Tenancy.md) application.
* **Users**: Used to abstract users, so other modules can depend on this instead of the Identity module.
Documenting the modules is in the progress. See [this repository](https://github.com/abpframework/abp/tree/master/modules) for source code of all modules.
Documenting the modules is in the progress. See [this repository](https://github.com/abpframework/abp/tree/master/modules) for source code of all modules.

3
docs/en/Modules/Permission-Management.md

@ -0,0 +1,3 @@
# Permission Management Module
TODO

11
docs/en/Multi-Tenancy.md

@ -114,7 +114,7 @@ namespace MyCompany.MyProject
{
Configure<TenantResolveOptions>(options =>
{
options.TenantResolvers.Add(new MyCustomTenantResolver());
options.TenantResolvers.Add(new MyCustomTenantResolveContributor());
});
//...
@ -123,14 +123,14 @@ namespace MyCompany.MyProject
}
````
MyCustomTenantResolver must implement **ITenantResolver** as shown below:
`MyCustomTenantResolveContributor` must implement **ITenantResolveContributor** as shown below:
````C#
using Volo.Abp.MultiTenancy;
namespace MyCompany.MyProject
{
public class MyCustomTenantResolver : ITenantResolver
public class MyCustomTenantResolveContributor : ITenantResolveContributor
{
public void Resolve(ITenantResolveContext context)
{
@ -307,6 +307,11 @@ Volo.Abp.AspNetCore.MultiTenancy package adds following tenant resolvers to dete
* **HeaderTenantResolver**: Tries to find current tenant id from HTTP header. Header name is "__tenant" by default.
* **CookieTenantResolver**: Tries to find current tenant id from cookie values. Cookie name is "__tenant" by default.
> If you use nginx as a reverse proxy server, please note that if `TenantKey` contains an underscore or other special characters, there may be a problem, please refer to:
http://nginx.org/en/docs/http/ngx_http_core_module.html#ignore_invalid_headers
http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers
"__tenant" parameter name can be changed using AspNetCoreMultiTenancyOptions. Example:
````C#

257
docs/en/Object-To-Object-Mapping.md

@ -1,3 +1,256 @@
## Object To Object Mapping
# Object To Object Mapping
It's common to map an object to another similar object. It's also tedious and repetitive since generally both classes have the same or similar properties mapped to each other. Imagine a typical [application service](Application-Services.md) method below:
```csharp
public class UserAppService : ApplicationService
{
private readonly IRepository<User, Guid> _userRepository;
public UserAppService(IRepository<User, Guid> userRepository)
{
_userRepository = userRepository;
}
public void CreateUser(CreateUserInput input)
{
//Manually creating a User object from the CreateUserInput object
var user = new User
{
Name = input.Name,
Surname = input.Surname,
EmailAddress = input.EmailAddress,
Password = input.Password
};
_userRepository.Insert(user);
}
}
```
`CreateUserInput ` is a simple [DTO](Data-Transfer-Objects.md) class and the `User` is a simple [entity](Entities.md). The code above creates a `User` entity from the given input object. The `User` entity will have more properties in a real-world application and manually creating it will become tedious and error-prone. You also have to change the mapping code when you add new properties to `User` and `CreateUserInput` classes.
We can use a library to automatically handle these kind of mappings. ABP provides abstractions for object to object mapping and has an integration package to use [AutoMapper](http://automapper.org/) as the object mapper.
## IObjectMapper
`IObjectMapper` interface (in the [Volo.Abp.ObjectMapping](https://www.nuget.org/packages/Volo.Abp.ObjectMapping) package) defines a simple `Map` method. The example code introduced before can be re-written as shown below:
````csharp
public class UserAppService : ApplicationService
{
private readonly IRepository<User, Guid> _userRepository;
public UserAppService(IRepository<User, Guid> userRepository)
{
_userRepository = userRepository;
}
public void CreateUser(CreateUserInput input)
{
//Automatically creating a new User object using the CreateUserInput object
var user = ObjectMapper.Map<CreateUserInput, User>(input);
_userRepository.Insert(user);
}
}
````
> `ObjectMapper` is defined in the `ApplicationService` base class in this example. You can directly inject the `IObjectMapper` interface when you need it somewhere else.
Map method has two generic argument: First one is the source object type while the second one is the destination object type.
If you need to set properties of an existing object, you can use the second overload of the `Map` method:
````csharp
public class UserAppService : ApplicationService
{
private readonly IRepository<User, Guid> _userRepository;
public UserAppService(IRepository<User, Guid> userRepository)
{
_userRepository = userRepository;
}
public async Task UpdateUserAsync(Guid id, UpdateUserInput input)
{
var user = await _userRepository.GetAsync(id);
//Automatically set properties of the user object using the UpdateUserInput
ObjectMapper.Map<UpdateUserInput, User>(input, user);
await _userRepository.UpdateAsync(user);
}
}
````
You should have defined the mappings before to be able to map objects. See the AutoMapper integration section to learn how to define mappings.
## AutoMapper Integration
[AutoMapper](http://automapper.org/) is one of the most popular object to object mapping libraries. [Volo.Abp.AutoMapper](https://www.nuget.org/packages/Volo.Abp.AutoMapper) package defines the AutoMapper integration for the `IObjectMapper`.
Once you define mappings described as below, you can use the `IObjectMapper` interface just like explained before.
### Define Mappings
AutoMapper provides multiple ways of defining mapping between classes. Refer to [its own documentation](https://docs.automapper.org) for all details.
One way to define object mappings is creating a [Profile](https://docs.automapper.org/en/stable/Configuration.html#profile-instances) class. Example:
````csharp
public class MyProfile : Profile
{
public MyProfile()
{
CreateMap<User, UserDto>();
}
}
````
You should then register profiles using the `AbpAutoMapperOptions`:
````csharp
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAutoMapperOptions>(options =>
{
//Add all mappings defined in the assembly of the MyModule class
options.AddMaps<MyModule>();
});
}
}
````
`AddMaps` registers all profile classes defined in the assembly of the given class, typically your module class. It also registers for the [attribute mapping](https://docs.automapper.org/en/stable/Attribute-mapping.html).
### Configuration Validation
`AddMaps` optionally takes a `bool` parameter to control the [configuration validation](https://docs.automapper.org/en/stable/Configuration-validation.html) for your [module](Module-Development-Basics.md):
````csharp
options.AddMaps<MyModule>(validate: true);
````
While this option is `false` by default, it is suggested to enable configuration validation as a best practice.
Configuration validation can be controlled per profile class using `AddProfile` instead of `AddMaps`:
````csharp
options.AddProfile<MyProfile>(validate: true);
````
> If you have multiple profiles and need to enable validation only for a few of them, first use `AddMaps` without validation, then use `AddProfile` for each profile you want to validate.
## Advanced Topics
### IObjectMapper<TContext> Interface
Assume that you have created a **reusable module** which defines AutoMapper profiles and uses `IObjectMapper` when it needs to map objects. Your module then can be used in different applications, by nature of the [modularity](Module-Development-Basics.md).
`IObjectMapper` is an abstraction and can be replaced by the final application to use another mapping library. The problem here that your reusable module is designed to use the AutoMapper library, because it only defines mappings for it. In such a case, you will want to guarantee that your module always uses AutoMapper even if the final application uses another default object mapping library.
`IObjectMapper<TContext>` is used to contextualize the object mapper, so you can use different libraries for different modules/contexts.
Example usage:
````csharp
public class UserAppService : ApplicationService
{
private readonly IRepository<User, Guid> _userRepository;
private readonly IObjectMapper<MyModule> _objectMapper;
public UserAppService(
IRepository<User, Guid> userRepository,
IObjectMapper<MyModule> objectMapper) //Inject module specific mapper
{
_userRepository = userRepository;
_objectMapper = objectMapper;
}
public async Task CreateUserAsync(CreateUserInput input)
{
//Use the module specific mapper
var user = _objectMapper.Map<CreateUserInput, User>(input);
await _userRepository.InsertAsync(user);
}
}
````
`UserAppService ` injects the `IObjectMapper<MyModule>`, the specific object mapper for this module. It's usage is exactly same of the `IObjectMapper`.
The example code above don't use the `ObjectMapper` property defined in the `ApplicationService`, but injects the `IObjectMapper<MyModule>`. However, it is still possible to use the base property since the `ApplicationService` defines an `ObjectMapperContext` property that can be set in the class constructor. So, the example about can be re-written as like below:
````csharp
public class UserAppService : ApplicationService
{
private readonly IRepository<User, Guid> _userRepository;
public UserAppService(IRepository<User, Guid> userRepository)
{
_userRepository = userRepository;
//Set the object mapper context
ObjectMapperContext = typeof(MyModule);
}
public async Task CreateUserAsync(CreateUserInput input)
{
var user = ObjectMapper.Map<CreateUserInput, User>(input);
await _userRepository.InsertAsync(user);
}
}
````
While using the contextualized object mapper is same as the normal object mapper, you should register the contextualized mapper in your module's `ConfigureServices` method:
````csharp
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//Use AutoMapper for MyModule
context.Services.AddAutoMapperObjectMapper<MyModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<MyModule>(validate: true);
});
}
}
````
`IObjectMapper<MyModule>` is an essential feature for a reusable module where it can be used in multiple applications each may use a different library for object to object mapping. All pre-built ABP modules are using it. But, for the final application, you can ignore this interface and always use the default `IObjectMapper` interface.
### IObjectMapper<TSource, TDestination> Interface
ABP allows you to customize the mapping code for specific classes. Assume that you want to create a custom class to map from `User` to `UserDto`. In this case, you can create a class that implements the `IObjectMapper<User, UserDto>`:
````csharp
public class MyCustomUserMapper : IObjectMapper<User, UserDto>, ITransientDependency
{
public UserDto Map(User source)
{
//TODO: Create a new UserDto
}
public UserDto Map(User source, UserDto destination)
{
//TODO: Set properties of an existing UserDto
return destination;
}
}
````
ABP automatically discovers and registers the `MyCustomUserMapper` and it is automatically used whenever you use the `IObjectMapper` to map `User` to `UserDto`.
A single class may implement more than one `IObjectMapper<TSource, TDestination>` each for a different object pairs.
> This approach is powerful since `MyCustomUserMapper` can inject any other service and use in the `Map` methods.
TODO

2
docs/en/Startup-Templates/Module.md

@ -25,7 +25,7 @@ abp new Acme.IssueManagement -t module
The template comes with an MVC UI by default. You can use `--no-ui` option to not include the UI layer.
````bash
abp new Acme.IssueManagement -t mvc-module --no-ui
abp new Acme.IssueManagement -t module --no-ui
````
## Solution Structure

10
docs/en/docs-nav.json

@ -82,10 +82,12 @@
"text": "Validation"
},
{
"text": "Authorization"
"text": "Authorization",
"path": "Authorization.md"
},
{
"text": "Caching"
"text": "Caching",
"path": "Caching.md"
},
{
"text": "Auditing"
@ -114,6 +116,10 @@
{
"text": "Services",
"items": [
{
"text": "Object to object mapping",
"path": "Object-To-Object-Mapping.md"
},
{
"text": "Object Serialization"
},

BIN
docs/en/images/authorization-new-permission-ui-hierarcy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
docs/en/images/authorization-new-permission-ui-localized.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/en/images/authorization-new-permission-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

31
docs/es/Index.md

@ -0,0 +1,31 @@
# Documentación de ABP
ABP es un **marco de desarrollo de código abierto** enfocado en el desarrollo de aplicaciones web basadas en ASP.NET Core, pero tambien soporta el desarrollo de otro tipo de aplicaciones.
Explora el menú de navegación de la izquierda para profundizar en la documentación.
## Estado del proyecto
ABP es la **próxima generación** del marco de desarrollo de código abierto [ASP.NET Boilerplate](https://aspnetboilerplate.com/). Actualmente se encuentra en una fase preliminar y no está listo para su uso en producción. La documentación todavía está en progreso y se encuentra lejos de estar completa.
Para aplicaciones en fase de producción o que lo vayan a estar en el corto plazo, se sugiere usar el marco de desarrollo [ASP.NET Boilerplate](https://aspnetboilerplate.com/) el cual tiene un completo conjunto de funciones, es maduro, mantenido y actualizado activamente.
## Primeros pasos
La manera más facil para iniciar un proyecto con ABP es usar las plantillas de inicio:
* [Plantilla ASP.NET Core MVC (Razor Pages) UI](Getting-Started-AspNetCore-MVC-Template.md)
* [Plantilla Angular UI](Getting-Started-Angular-Template.md)
Si quieres iniciar desde cero (con un proyecto vacío), entonces instala manualmente el marco de desarrollo ABP y usa los siguientes tutoriales:
* [Aplicación de Consola](Getting-Started-Console-Application.md)
* [Aplicación web con ASP.NET Core](Getting-Started-AspNetCore-Application.md)
## Código fuente
ABP está hospedado en GitHub. Mira el [código fuente](https://github.com/abpframework/abp).
## ¿Quieres contribuir?
ABP es un proyecto de código abierto impulsado por la comunidad. Mira la [guía de contribución](Contribution/Index.md) si quieres formar parte de este proyecto.

3
docs/pt-BR/Aspect-Oriented-Programming.md

@ -0,0 +1,3 @@
## Dynamic Proxying / Interceptors
Façam

3
docs/pt-BR/Audit-Logging.md

@ -0,0 +1,3 @@
# Audit Logging
Façam

3
docs/pt-BR/Authorization.md

@ -0,0 +1,3 @@
## Authorization
Façam

3
docs/pt-BR/AutoMapper-Integration.md

@ -0,0 +1,3 @@
## AutoMapper Integration
Façam

3
docs/pt-BR/Background-Jobs-Hangfire.md

@ -0,0 +1,3 @@
# Hangfire Background Job Manager
Façam

3
docs/pt-BR/Background-Jobs-RabbitMq.md

@ -0,0 +1,3 @@
# RabbitMQ Background Job Manager
TODO

149
docs/pt-BR/CLI.md

@ -0,0 +1,149 @@
# ABP CLI
O ABP CLI (Command Line Interface) é uma ferramenta de linha de comando para executar algumas operações comuns para soluções baseadas em ABP.
## Instalação
O ABP CLI é uma [ferramenta global dotnet](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools) . Instale-o usando uma janela de linha de comando:
````bash
dotnet tool install -g Volo.Abp.Cli
````
Para atualizar uma instalação existente:
````bash
dotnet tool update -g Volo.Abp.Cli
````
## Comandos
### Novo
Gera uma nova solução baseada nos [modelos de inicialização](Startup-Templates/Index.md) do ABP .
Uso básico:
````bash
abp new <solution-name> [options]
````
Examplo:
````bash
abp new Acme.BookStore
````
* `Acme.BookStore` é o nome da solução aqui.
* A convenção comum é nomear uma solução como *YourCompany.YourProject* . No entanto, você pode usar nomes diferentes, como *YourProject* (namespacing de nível único) ou *YourCompany.YourProduct.YourModule* (namespacing de três níveis).
#### Opções
* `--template`ou `-t`: especifica o nome do modelo. O nome do modelo padrão é `app`, que gera um aplicativo da web. Modelos disponíveis:
* `app`(padrão): [modelo de aplicativo](https://docs.abp.io/en/abp/latest/Startup-Templates/Application) . Opções adicionais:
* `--ui`ou `-u`: Especifica a UI framework. Framework padrão é `mvc`. Framework disponíveis:
* `mvc`: ASP.NET Core MVC. Existem algumas opções adicionais para este modelo:
* `--tiered`: Cria uma solução em camadas em que as camadas da Web e da API HTTP são fisicamente separadas. Se não especificado, ele cria uma solução em camadas que é menos complexa e adequada para a maioria dos cenários.
* `angular`: Angular. Existem algumas opções adicionais para este modelo:
* `--separate-identity-server`: Separa o aplicativo do servidor de identidade do aplicativo host da API. Se não especificado, você terá um único ponto de extremidade no lado do servidor.
* `--database-provider` Ou `-d`: especifica o provedor de banco de dados. O provedor padrão é `ef`. Fornecedores disponíveis:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
* `module`: [Exemplo de Módulo](Startup-Templates/Module.md). Opções adicionais:
* `--no-ui`: Especifica para não incluir a UI. Isso possibilita a criação de módulos somente de serviço (também conhecidos como microsserviços - sem interface do usuário).
* `--output-folder` ou `-o`: especifica a pasta de saída. O valor padrão é o diretório atual.
* `--version` ou `-v`: Especifica a ABP & versão de exemplo . Pode ser uma [release tag](https://github.com/abpframework/abp/releases) ou um [branch name](https://github.com/abpframework/abp/branches). Usa a versão mais recente, se não especificado. Na maioria das vezes, você desejará usar a versão mais recente.
### add-package
Adiciona um pacote ABP a um projeto por,
- Adicionando pacote de nuget relacionado como uma dependência ao projeto.
- Adicionando `[DependsOn(...)]`atributo à classe de módulo no projeto (consulte o [documento de desenvolvimento](https://docs.abp.io/en/abp/latest/Module-Development-Basics) do [módulo](https://docs.abp.io/en/abp/latest/Module-Development-Basics) ).
> Observe que o módulo adicionado pode exigir uma configuração adicional, geralmente indicada na documentação do pacote relacionado.
Uso básico:
```bash
abp add-package <package-name> [options]
```
Bater
cópia de
Exemplo:
```
abp add-package Volo.Abp.MongoDB
```
- Este exemplo adiciona o pacote Volo.Abp.MongoDB ao projeto.
#### Opções
- `--project`ou `-p`: especifica o caminho do arquivo do projeto (.csproj). Se não especificado, a CLI tenta encontrar um arquivo .csproj no diretório atual.
### add-module
Adiciona um [módulo de aplicativo com vários pacotes](Modules/Index.md) a uma solução, localizando todos os pacotes do módulo, localizando projetos relacionados na solução e adicionando cada pacote ao projeto correspondente na solução.
> Um módulo de negócios geralmente consiste em vários pacotes (devido a camadas, diferentes opções de provedor de banco de dados ou outros motivos). O uso do `add-module`comando simplifica drasticamente a adição de um módulo a uma solução. No entanto, cada módulo pode exigir algumas configurações adicionais, geralmente indicadas na documentação do módulo relacionado.
Uso básico:
```bash
abp add-module <module-name> [options]
```
Exemplo:
```bash
abp add-module Volo.Blogging
```
- Este exemplo adiciona o módulo Volo.Blogging à solução.
#### Opções
- `--solution`ou `-s`: especifica o caminho do arquivo da solução (.sln). Se não especificado, a CLI tenta encontrar um arquivo .sln no diretório atual.
- `--skip-db-migrations`: Para o provedor de banco de dados EF Core, ele adiciona automaticamente um novo código à primeira migração ( `Add-Migration`) e atualiza o banco de dados ( `Update-Database`), se necessário. Especifique esta opção para pular esta operação.
- `-sp`ou `--startup-project`: caminho relativo para a pasta do projeto de inicialização. O valor padrão é a pasta atual.
### atualizar
A atualização de todos os pacotes relacionados ao ABP pode ser entediante, pois existem muitos pacotes da estrutura e dos módulos. Este comando atualiza automaticamente todos os pacotes NuGet e NPM relacionados ao ABP em uma solução ou projeto para as versões mais recentes.
Uso:
```bash
abp update [options]
```
- Se você executar em um diretório com um arquivo .sln, ele atualizará todos os pacotes relacionados ao ABP de todos os projetos da solução para as versões mais recentes.
- Se você executar em um diretório com um arquivo .csproj, ele atualizará todos os pacotes relacionados ao ABP do projeto para as versões mais recentes.
#### Opções
- `--include-previews`ou `-p`: inclui pacotes de visualização, beta e rc enquanto verifica as versões mais recentes.
### Socorro
Grava informações básicas de uso da CLI.
Uso:
```bash
abp help [command-name]
```
Exemplos:
```bash
abp help # Shows a general help.
abp help new # Shows help about the "new" command.
```

3
docs/pt-BR/Caching.md

@ -0,0 +1,3 @@
# Caching
Façam

60
docs/pt-BR/Contribution/Index.md

@ -0,0 +1,60 @@
## Guia de Contribuição
O ABP é um projeto de [código aberto](https://github.com/abpframework) e orientado à comunidade. Este guia tem como objetivo ajudar alguém que queira contribuir com o projeto.
### Contribuição de código
Você sempre pode enviar solicitações pull ao repositório do Github.
- Clone o [repositório ABP](https://github.com/abpframework/abp/) do Github.
- Faça as alterações necessárias.
- Envie uma solicitação de recebimento.
Antes de fazer qualquer alteração, discuta-a sobre os [problemas](https://github.com/abpframework/abp/issues) do [Github](https://github.com/abpframework/abp/issues) . Dessa forma, nenhum outro desenvolvedor trabalhará no mesmo problema e seu PR terá uma chance melhor de ser aceito.
#### Correções de bugs e aprimoramentos
Você pode corrigir um bug conhecido ou trabalhar em uma melhoria planejada. Veja [a lista de problemas](https://github.com/abpframework/abp/issues) no Github.
#### Solicitações de recursos
Se você tem uma ideia de recurso para a estrutura ou módulos, [crie um problema](https://github.com/abpframework/abp/issues/new) no Github ou participe de uma discussão existente. Então você pode implementá-lo se for adotado pela comunidade.
### Tradução de documentos
Você pode traduzir a [documentação](https://abp.io/documents/) completa (incluindo esta) para o idioma materno. Nesse caso, siga estas etapas:
- Clone o [repositório ABP](https://github.com/abpframework/abp/) do Github.
- Para adicionar um novo idioma, crie uma nova pasta dentro da pasta [docs](https://github.com/abpframework/abp/tree/master/docs) . Os nomes das pastas podem ser "en", "es", "fr", "tr" e assim por diante, com base no idioma (consulte [todos os códigos de cultura](https://msdn.microsoft.com/en-us/library/hh441729.aspx) ).
- Obtenha a [pasta "en"](https://github.com/abpframework/abp/tree/master/docs/en) como uma referência para os nomes de arquivos e a estrutura de pastas. Mantenha o mesmo nome se estiver traduzindo a mesma documentação.
- Envie uma solicitação de recebimento (PR) depois de traduzir qualquer documento. Traduza documentos e envie PRs um por um. Não espere para terminar as traduções de todos os documentos.
Alguns documentos fundamentais precisam ser traduzidos antes da publicação de um idioma no [site de documentação](https://docs.abp.io/) da [ABP](https://docs.abp.io/) :
- Documentos de introdução
- Tutoriais
- CLI
Um novo idioma é publicado após a conclusão dessas traduções mínimas.
### Localização de Recursos
A estrutura ABP possui um [sistema de localização](../Localization.md) flexível . Você pode criar interfaces de usuário localizadas para seu próprio aplicativo.
Além disso, os módulos de estrutura e pré-construção já localizaram textos. Como exemplo, veja [os textos de localização para o pacote Volo.Abp.UI](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json) . Você pode criar um novo arquivo na [mesma pasta](https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi) para traduzi-lo.
- Clone o [repositório ABP](https://github.com/abpframework/abp/) do Github.
- Crie um novo arquivo para o idioma de destino para um arquivo de texto de localização (json) (próximo ao arquivo en.json).
- Copie todos os textos do arquivo en.json.
- Traduzir os textos.
- Enviar solicitação de recebimento no Github.
ABP é uma estrutura modular. Portanto, existem muitos recursos de texto de localização, um por módulo. Para encontrar todos os arquivos .json, você pode procurar por "en.json" após clonar o repositório. Você também pode verificar [esta lista](https://docs.abp.io/en/abp/latest/Contribution/Localization-Text-Files) para obter uma lista de arquivos de texto de localização.
### Posts e tutoriais do blog
Se você decidir criar alguns tutoriais ou postagens de blog no ABP, informe-nos (criando um [problema no Github](https://github.com/abpframework/abp/issues) ), para que possamos adicionar um link ao seu tutorial / publicação na documentação oficial e podemos anunciá-lo em nossa [conta do Twitter](https://twitter.com/abpframework) .
### Relatório de erro
Se você encontrar algum erro, [crie um problema no repositório do Github](https://github.com/abpframework/abp/issues/new) .

3
docs/pt-BR/CorrelationId.md

@ -0,0 +1,3 @@
# Correlation ID
Façam

3
docs/pt-BR/Data-Filtering.md

@ -0,0 +1,3 @@
# Data Filtering
Façam

3
docs/pt-BR/Data-Seeding.md

@ -0,0 +1,3 @@
# Data Seeding
Façam

3
docs/pt-BR/Data-Transfer-Objects.md

@ -0,0 +1,3 @@
## Data Transfer Objects
Façam

3
docs/pt-BR/Distributed-Event-Bus.md

@ -0,0 +1,3 @@
# Distributed Event Bus
Façam

3
docs/pt-BR/Domain-Services.md

@ -0,0 +1,3 @@
# ABP Documentation
Façam!

3
docs/pt-BR/Dynamic-Proxying-Interceptors.md

@ -0,0 +1,3 @@
## Dynamic Proxying / Interceptors
Façam

3
docs/pt-BR/Emailing.md

@ -0,0 +1,3 @@
# Emailing
Façam!

3
docs/pt-BR/Event-Bus.md

@ -0,0 +1,3 @@
# Event Bus
Façam

3
docs/pt-BR/Extension-Methods-And-Helpers.md

@ -0,0 +1,3 @@
# Extension Methods & Helpers
Façam

126
docs/pt-BR/Getting-Started-Angular-Template.md

@ -0,0 +1,126 @@
## Introdução ao modelo de aplicativo Angular
Este tutorial explica como criar um novo aplicativo Angular usando o modelo de inicialização, configurar e executá-lo.
### Criando um novo projeto
Este tutorial usa o **ABP CLI** para criar um novo projeto. Consulte a página [Introdução](https://abp.io/get-started) para outras opções.
Instale a CLI ABP usando uma janela de linha de comando, se você não tiver instalado antes:
```bash
dotnet tool install -g Volo.Abp.Cli
```
Use o `abp new`comando em uma pasta vazia para criar seu projeto:
```bash
abp new Acme.BookStore -u angular
```
> Você pode usar diferentes níveis de namespaces; por exemplo, BookStore, Acme.BookStore ou Acme.Retail.BookStore.
`-u angular`A opção especifica que a estrutura da interface do usuário seja Angular. O provedor de banco de dados padrão é o EF Core. Consulte a [documentação](CLI.md) da [CLI](CLI.md) para todas as opções disponíveis.
#### Pré requisitos
A solução criada requer;
- [Visual Studio 2017 (v15.9.0 +)](https://visualstudio.microsoft.com/tr/downloads/)
- [.NET Core 2.2 ou superior](https://www.microsoft.com/net/download/dotnet-core/)
- [Node v10.16 +](https://nodejs.org/)
- [Yarn v1.17 +](https://yarnpkg.com/)
### A Estrutura da Solução
Abra a solução no **Visual Studio** :
![livraria-visual-studio-solução](images/bookstore-visual-studio-solution-for-spa.png)
A solução possui uma estrutura em camadas (baseada no [Domain Driven Design](Domain-Driven-Design.md) ) e contém projetos de teste de unidade e integração adequadamente configurados para trabalhar com o **banco de dados** **EF Core** & **SQLite in-memory**.
> Consulte o [documento do modelo do aplicativo](Startup-Templates/Application.md) para entender a estrutura da solução em detalhes.
### String de Conexão de Banco de Dados
Verifique o **connection string** no `appsettings.json`arquivo no `.HttpApi.Host`projeto:
```json
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
}
}
```
A solução está configurada para usar o **Entity Framework Core** com o **MS SQL Server** . O EF Core suporta [vários](https://docs.microsoft.com/en-us/ef/core/providers/) provedores de banco de dados, para que você possa usar outro DBMS, se desejar. Mude a cadeia de conexão, se necessário.
### Criar banco de dados e aplicar migrações de banco de dados
Você tem duas opções para criar o banco de dados.
#### Usando o aplicativo DbMigrator
A solução contém um aplicativo de console (nomeado `Acme.BookStore.DbMigrator`nesta amostra) que pode criar banco de dados, aplicar migrações e propagar dados iniciais. É útil no desenvolvimento e no ambiente de produção.
> `.DbMigrator`projeto tem o seu próprio `appsettings.json`. Portanto, se você alterou a cadeia de conexão acima, também deve alterar esta.
Clique com o botão direito do mouse no `.DbMigrator`projeto e selecione **Definir como Projeto de Inicialização** :
![definir como projeto de inicialização](images/set-as-startup-project.png)
Pressione F5 (ou Ctrl + F5) para executar o aplicativo. Terá uma saída como mostrado abaixo:
![definir como projeto de inicialização](images/db-migrator-app.png)
#### Usando o comando EF Core Update-Database
O Ef Core possui um `Update-Database`comando que cria banco de dados, se necessário, e aplica migrações pendentes. Clique com o botão direito do mouse no `.Web`projeto e selecione **Definir como Projeto de Inicialização** :
![definir como projeto de inicialização](images/set-as-startup-project.png)
Abra o **Console do Gerenciador de Pacotes** , selecione o `.EntityFrameworkCore.DbMigrations`projeto como **Projeto Padrão** e execute o `Update-Database`comando:
![pcm-update-database](images/pcm-update-database-v2.png)
Isso criará um novo banco de dados com base na cadeia de conexão configurada.
> O uso da `.Migrator`ferramenta é a maneira sugerida, porque também semeia os dados iniciais para poder executar corretamente o aplicativo Web.
### Executando o aplicativo
#### Execute o host da API (lado do servidor)
Verifique se o `.HttpApi.Host`projeto é o projeto de inicialização e o aplicativo que abrirá uma interface do usuário do Swagger:
![livraria-homepage](images/bookstore-swagger-ui-host.png)
Você pode ver as APIs do aplicativo e testá-las aqui. Obtenha [mais informações](https://swagger.io/tools/swagger-ui/) sobre a interface do usuário do Swagger.
##### Autorização para a interface do usuário do Swagger
A maioria das APIs de aplicativos requer autenticação e autorização. Se você deseja testar APIs autorizadas, vá manualmente para a `/Account/Login`página, digite `admin`como o nome de usuário e `1q2w3E*`a senha para efetuar login no aplicativo. Você também poderá executar APIs autorizadas.
#### Execute o aplicativo angular (lado do cliente)
Vá para a `angular`pasta, abra um terminal de linha de comando, digite o `yarn`comando (sugerimos ao gerenciador de pacotes do [yarn](https://yarnpkg.com/) enquanto o npm install também funcionará na maioria dos casos):
```bash
yarn
```
Depois que todos os módulos do nó estiverem carregados, execute `yarn start`ou `npm start`comando:
```bash
yarn start
```
Abra seu navegador favorito e vá para `localhost:4200`URL. Nome de usuário inicial é `admin`e senha é `1q2w3E*`.
O modelo de inicialização inclui os módulos de **gerenciamento de** **identidade** e **gerenciamento de inquilino** . Após o login, o menu Administração estará disponível, onde você poderá gerenciar **inquilinos** , **funções** , **usuários** e suas **permissões** .
> Recomendamos o [Visual Studio Code](https://code.visualstudio.com/) como editor do projeto Angular, mas você pode usar seu editor favorito.
### Qual é o próximo?
- [Tutorial de desenvolvimento de aplicativos](Tutorials/Angular/Part-I.md)

183
docs/pt-BR/Getting-Started-AspNetCore-Application.md

@ -0,0 +1,183 @@
# Introdução ao ABP com o AspNet Core MVC Web Application
Este tutorial explica como iniciar o ABP do zero com dependências mínimas. Você geralmente deseja começar com o **modelo de inicialização** .
## Criar um novo projeto
1. Crie um novo aplicativo da Web vazio AspNet Core Web Application no Visual Studio:
![img](images/create-new-aspnet-core-application.png)
1. Selecionar modelo vazio
![img](images/select-empty-web-application.png)
Você pode selecionar outro modelo, mas quero mostrá-lo em um projeto claro.
## Instale o pacote Volo.Abp.AspNetCore.Mvc
Volo.Abp.AspNetCore.Mvc é um pacote de integração do AspNet Core MVC para ABP. Então, instale-o no seu projeto:
```
Install-Package Volo.Abp.AspNetCore.Mvc
```
## Criar o primeiro módulo ABP
O ABP é uma estrutura modular e requer uma classe de **módulo de inicialização (raiz)** derivada de `AbpModule`:
```csharp
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.AspNetCore.Modularity;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
namespace BasicAspNetCoreApplication
{
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
public class AppModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvcWithDefaultRoute();
}
}
}
```
`AppModule` é um bom nome para o módulo de inicialização de um aplicativo.
Os pacotes ABP definem as classes do módulo e um módulo pode depender de outro módulo. No código acima, nosso `AppModule` depende `AbpAspNetCoreMvcModule`(definido pelo pacote Volo.Abp.AspNetCore.Mvc). É comum adicionar um `DependsOn`atributo após a instalação de um novo pacote de nuget ABP.
Em vez da classe Startup, estamos configurando o pipeline do ASP.NET Core nesta classe de módulo.
## A classe de inicialização
O próximo passo é modificar a classe Startup para integrar ao sistema do módulo ABP:
```csharp
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace BasicAspNetCoreApplication
{
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddApplication<AppModule>();
return services.BuildServiceProviderFromFactory();
}
public void Configure(IApplicationBuilder app)
{
app.InitializeApplication();
}
}
}
```
`ConfigureServices` Método alterado para retornar em `IServiceProvider` vez de `void`. Essa alteração nos permite substituir a injeção de dependência do AspNet Core por outra estrutura (consulte a seção de integração com Autofac abaixo). `services.AddApplication<AppModule>()` adiciona todos os serviços definidos em todos os módulos a partir do `AppModule`.
`app.InitializeApplication()`O `Configure`método call in inicializa e inicia o aplicativo.
## Olá Mundo!
O aplicativo acima não faz nada. Vamos criar um controlador MVC que faz algo:
```csharp
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace BasicAspNetCoreApplication.Controllers
{
public class HomeController : AbpController
{
public IActionResult Index()
{
return Content("Hello World!");
}
}
}
```
Se você executar o aplicativo, verá um "Olá, mundo!" mensagem na página.
Derivado `HomeController`de em `AbpController`vez de `Controller`classe padrão . Isso não é necessário, mas a `AbpController`classe possui propriedades e métodos base úteis para facilitar seu desenvolvimento.
## Usando Autofac como framework de injeção de dependência
Embora o sistema de Injeção de Dependência (DI) do AspNet Core seja adequado para requisitos básicos, o Autofac fornece recursos avançados, como Injeção de Propriedade e Interceptação de Método, exigidos pela ABP para executar recursos avançados da estrutura de aplicativos.
Substituir o sistema DI do AspNet Core pelo Autofac e integrar ao ABP é bastante fácil.
1. Instale o pacote [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac)
```
Install-Package Volo.Abp.Autofac
```
1. Adicionar `AbpAutofacModule` dependência
```csharp
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
[DependsOn(typeof(AbpAutofacModule))] //Add dependency to ABP Autofac module
public class AppModule : AbpModule
{
...
}
```
1. Altere a `services.AddApplication<AppModule>();` linha na `Startup`classe, como mostrado abaixo:
```csharp
services.AddApplication<AppModule>(options =>
{
options.UseAutofac(); //Integrate to Autofac
});
```
1. Atualize `Program.cs` para não usar o `WebHost.CreateDefaultBuilder()` método, pois ele usa o contêiner DI padrão:
```csharp
public class Program
{
public static void Main(string[] args)
{
/*
https://github.com/aspnet/AspNetCore/issues/4206#issuecomment-445612167
CurrentDirectoryHelpers exists in: \framework\src\Volo.Abp.AspNetCore.Mvc\Microsoft\AspNetCore\InProcess\CurrentDirectoryHelpers.cs
Will remove CurrentDirectoryHelpers.cs when upgrade to ASP.NET Core 3.0.
*/
CurrentDirectoryHelpers.SetCurrentDirectory();
BuildWebHostInternal(args).Run();
}
public static IWebHost BuildWebHostInternal(string[] args) =>
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIIS()
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
}
```
## Código fonte
Obter código-fonte do projeto de exemplo criada neste tutorial a partir de [aqui](https://github.com/abpframework/abp/tree/master/samples/BasicAspNetCoreApplication) .

102
docs/pt-BR/Getting-Started-AspNetCore-MVC-Template.md

@ -0,0 +1,102 @@
## Introdução ao modelo ASP.NET Core MVC
Este tutorial explica como criar um novo aplicativo Web ASP.NET Core MVC usando o modelo de inicialização, configurá-lo e executá-lo.
### Criando um novo projeto
Este tutorial usa o **ABP CLI** para criar um novo projeto. Consulte a página [Introdução](https://abp.io/get-started) para outras opções.
Instale a CLI ABP usando uma janela de linha de comando, se você não tiver instalado antes:
```bash
dotnet tool install -g Volo.Abp.Cli
```
Use o `abp new`comando em uma pasta vazia para criar seu projeto:
```bash
abp new Acme.BookStore
```
> Você pode usar diferentes níveis de namespaces; por exemplo, BookStore, Acme.BookStore ou Acme.Retail.BookStore.
`new` O comando cria um **aplicativo MVC em camadas** com o **Entity Framework Core** como o provedor de banco de dados. No entanto, possui opções adicionais. Consulte a [documentação](CLI.md) da [CLI](CLI.md) para todas as opções disponíveis.
#### Pré requisitos
A solução criada requer;
- [Visual Studio 2017 (v15.9.0 +)](https://visualstudio.microsoft.com/tr/downloads/)
- [.NET Core 2.2 ou superior](https://www.microsoft.com/net/download/dotnet-core/)
### A Estrutura da Solução
Abra a solução no **Visual Studio** :
![livraria-visual-studio-solução](images/bookstore-visual-studio-solution-v3.png)
A solução possui uma estrutura em camadas (baseada no [Domain Driven Design](Domain-Driven-Design.md) ) e contém projetos de teste de unidade e integração adequadamente configurados para trabalhar com o **banco de** dados de **memória** **EF Core** e **SQLite** .
> Consulte o [documento do modelo de aplicativo](Startup-Templates/Application.md) para entender a estrutura da solução em detalhes.
### Cadeia de Conexão de Banco de Dados
Verifique a **connection string** no `appsettings.json`arquivo no `.Web`projeto:
```json
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
}
}
```
A solução está configurada para usar o **Entity Framework Core** com o **MS SQL Server** . O EF Core suporta [vários](https://docs.microsoft.com/en-us/ef/core/providers/) provedores de banco de dados, para que você possa usar outro DBMS, se desejar. Mude a cadeia de conexão, se necessário.
### Criar banco de dados e aplicar migrações de banco de dados
Você tem duas opções para criar o banco de dados.
#### Usando o aplicativo DbMigrator
A solução contém um aplicativo de console (nomeado `Acme.BookStore.DbMigrator`nesta amostra) que pode criar banco de dados, aplicar migrações e propagar dados iniciais. É útil no desenvolvimento e no ambiente de produção.
> `.DbMigrator`projeto tem o seu próprio `appsettings.json`. Portanto, se você alterou a cadeia de conexão acima, também deve alterar esta.
Clique com o botão direito do mouse no `.DbMigrator`projeto e selecione **Definir como Projeto de Inicialização** :
![definir como projeto de inicialização](images/set-as-startup-project.png)
Pressione F5 (ou Ctrl + F5) para executar o aplicativo. Terá uma saída como mostrado abaixo:
![definir como projeto de inicialização](images/db-migrator-app.png)
#### Usando o comando EF Core Update-Database
O Ef Core possui um `Update-Database`comando que cria banco de dados, se necessário, e aplica migrações pendentes. Clique com o botão direito do mouse no `.Web`projeto e selecione **Definir como Projeto de Inicialização** :
![definir como projeto de inicialização](images/set-as-startup-project.png)
Abra o **Console do Gerenciador de Pacotes** , selecione o `.EntityFrameworkCore.DbMigrations`projeto como **Projeto Padrão** e execute o `Update-Database`comando:
![pcm-update-database](images/pcm-update-database-v2.png)
Isso criará um novo banco de dados com base na cadeia de conexão configurada.
> O uso da `.Migrator`ferramenta é a maneira sugerida, porque também semeia os dados iniciais para poder executar corretamente o aplicativo Web.
### Executando o aplicativo
Verifique se o `.Web`projeto é o projeto de inicialização. Execute o aplicativo que abrirá a página **inicial** no seu navegador:
![livraria-homepage](images/bookstore-homepage.png)
Clique no botão **Login** , insira `admin` como nome de usuário e `1q2w3E*` senha para acessar o aplicativo.
O modelo de inicialização inclui os módulos de **gerenciamento de** **identidade** e **gerenciamento de inquilino** . Após o login, o menu Administração estará disponível, onde você poderá gerenciar **inquilinos** , **funções** , **usuários** e suas **permissões** . A página de gerenciamento de usuários é mostrada abaixo:
![livraria-gerenciamento de usuários](images/bookstore-user-management-v2.png)
### Qual é o próximo?
- [Tutorial de desenvolvimento de aplicativos](Tutorials/AspNetCore-Mvc/Part-I.md)

181
docs/pt-BR/Getting-Started-Console-Application.md

@ -0,0 +1,181 @@
# Introdução ao ABP com aplicativo de console
Este tutorial explica como iniciar o ABP do zero com dependências mínimas. Você geralmente deseja começar com um **modelo de inicialização** .
## Criar um novo projeto
Crie um novo aplicativo regular .Net Core Console do Visual Studio:
![img](images/create-new-net-core-console-application.png)
## Instale o pacote Volo.Abp
Volo.Abp.Core é o pacote principal de nuget para criar aplicativos baseados em ABP. Então, instale-o no seu projeto:
```
Install-Package Volo.Abp.Core
```
## Criar o primeiro módulo ABP
O ABP é um framework modular e requer uma classe de **módulo de inicialização (raiz)** derivada de `AbpModule`:
```csharp
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace AbpConsoleDemo
{
public class AppModule : AbpModule
{
}
}
```
`AppModule` é um bom nome para o módulo de inicialização de um aplicativo.
## Inicializar o aplicativo
A próxima etapa é inicializar o aplicativo usando o módulo de inicialização criado acima:
```csharp
using System;
using Volo.Abp;
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>())
{
application.Initialize();
Console.WriteLine("Press ENTER to stop application...");
Console.ReadLine();
}
}
}
}
```
`AbpApplicationFactory`é usado para criar o aplicativo e carregar todos os módulos que tomam `AppModule`como módulo de inicialização. `Initialize()`O método inicia o aplicativo.
## Olá Mundo!
O aplicativo acima não faz nada. Vamos criar um serviço que faça algo:
```csharp
using System;
using Volo.Abp.DependencyInjection;
namespace AbpConsoleDemo
{
public class HelloWorldService : ITransientDependency
{
public void SayHello()
{
Console.WriteLine("Hello World!");
}
}
}
```
`ITransientDependency`é uma interface especial do ABP que registra automaticamente o serviço como transitório (consulte o [documento de injeção de dependência](Dependency-Injection.md) ).
Agora, podemos resolver o problema `HelloWorldService`e dizer olá. Altere o Program.cs como mostrado abaixo:
```csharp
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>())
{
application.Initialize();
//Resolve a service and use it
var helloWorldService =
application.ServiceProvider.GetService<HelloWorldService>();
helloWorldService.SayHello();
Console.WriteLine("Press ENTER to stop application...");
Console.ReadLine();
}
}
}
}
```
Embora seja suficiente para este exemplo de código simples, é sempre recomendável criar escopos no caso de resolver diretamente dependências de `IServiceProvider`(consulte a [documentação de Injeção de Dependências](Dependency-Injection.md)).
## Usando Autofac como framework de injeção de dependência
Embora o sistema de Injeção de Dependência (DI) do AspNet Core seja adequado para requisitos básicos, o Autofac fornece recursos avançados, como Injeção de Propriedade e Interceptação de Método, exigidos pela ABP para executar recursos avançados do framework de aplicativos.
Substituir o sistema DI do AspNet Core pelo Autofac e integrar ao ABP é bastante fácil.
1. Instale o pacote [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac)
```
Install-Package Volo.Abp.Autofac
```
1. Adicionar `AbpAutofacModule`dependência
```csharp
[DependsOn(typeof(AbpAutofacModule))] //Add dependency to the AbpAutofacModule
public class AppModule : AbpModule
{
}
```
1. Mude o `Program.cs`arquivo como mostrado abaixo:
```csharp
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>(options =>
{
options.UseAutofac(); //Autofac integration
}))
{
application.Initialize();
//Resolve a service and use it
var helloWorldService =
application.ServiceProvider.GetService<HelloWorldService>();
helloWorldService.SayHello();
Console.WriteLine("Press ENTER to stop application...");
Console.ReadLine();
}
}
}
}
```
Apenas chamado `options.UseAutofac()`método nas `AbpApplicationFactory.Create`opções.
## Código fonte
Obter código-fonte do projeto de exemplo criada neste tutorial a partir de [aqui](https://github.com/abpframework/abp/tree/master/samples/BasicConsoleApplication) .

3
docs/pt-BR/Guid-Generation.md

@ -0,0 +1,3 @@
## Guid Generation
Façam

31
docs/pt-BR/Index.md

@ -0,0 +1,31 @@
# Documentação ABP
O ABP é um **framework de aplicativos de código aberto** focada no desenvolvimento de aplicativos da Web baseado no ASP.NET Core, mas também suporta o desenvolvimento de outros tipos de aplicativos.
Explore o menu de navegação esquerdo para mergulhar fundo na documentação.
## Status do projeto
ABP é a **próxima geração** de framework de código aberto [ASP.NET Boilerplate](https://aspnetboilerplate.com/). Atualmente, está em fase de pré-visualização e não está pronto para uso na produção. A documentação ainda está em andamento e está longe de estar completa.
Para aplicativos de curto prazo e em nível de produção, é sugerido o uso da estrutura do [ASP.NET Boilerplate](https://aspnetboilerplate.com/) , que possui um rico conjunto de recursos, maduro, mantido ativamente e atualizado.
## Começando
A maneira mais fácil de iniciar um novo projeto com o ABP é usar os modelos de inicialização:
- [Modelo de interface do usuário do ASP.NET Core MVC (Razor Pages)](Getting-Started-AspNetCore-MVC-Template.md)
- [Modelo de interface do usuário angular](Getting-Started-Angular-Template.md)
Se você deseja começar do zero (com um projeto vazio), instale manualmente o ABP Framework e use os seguintes tutoriais:
- [Aplicação de console](Getting-Started-Console-Application.md)
- [Aplicativo da Web principal do ASP.NET](Getting-Started-AspNetCore-Application.md)
## Código fonte
ABP está hospedado no GitHub. Veja [o código fonte](https://github.com/abpframework/abp) .
## Deseja contribuir?
O ABP é um projeto de código aberto orientado pela comunidade. Consulte [o guia de contribuição](Contribution/Index.md) se você quiser fazer parte deste projeto.

3
docs/pt-BR/Integration-Tests.md

@ -0,0 +1,3 @@
# Integration Tests
Façam!

3
docs/pt-BR/Local-Event-Bus.md

@ -0,0 +1,3 @@
# Local Event Bus
Façam

195
docs/pt-BR/Localization.md

@ -0,0 +1,195 @@
# Localização
O sistema de localização da ABP é perfeitamente integrado ao `Microsoft.Extensions.Localization`pacote e compatível com a [documentação de localização da Microsoft](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) . Ele adiciona alguns recursos e aprimoramentos úteis para facilitar o uso em cenários de aplicativos da vida real.
## Pacote Volo.Abp.Localization
> Este pacote já está instalado por padrão com o modelo de inicialização. Portanto, na maioria das vezes, você não precisa instalá-lo manualmente.
Volo.Abp.Localization é o pacote principal do sistema de localização. Instale-o no seu projeto usando o console do gerenciador de pacotes (PMC):
```
Install-Package Volo.Abp.Localization
```
Em seguida, você pode adicionar a dependência **AbpLocalizationModule** ao seu módulo:
```csharp
using Volo.Abp.Modularity;
using Volo.Abp.Localization;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpLocalizationModule))]
public class MyModule : AbpModule
{
//...
}
}
```
## Criando um recurso de localização
Um recurso de localização é usado para agrupar cadeias de localização relacionadas e separá-las de outras cadeias de localização do aplicativo. Um [módulo](Module-Development-Basics.md) geralmente define seu próprio recurso de localização. O recurso de localização é apenas uma classe simples. Exemplo:
```csharp
public class TestResource
{
}
```
Em seguida, deve ser adicionado usando `AbpLocalizationOptions`como mostrado abaixo:
```csharp
[DependsOn(typeof(AbpLocalizationModule))]
public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<VirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<MyModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
//Define a new localization resource (TestResource)
options.Resources
.Add<TestResource>("en")
.AddVirtualJson("/Localization/Resources/Test");
});
}
}
```
Neste exemplo;
- Adicionado um novo recurso de localização com "en" (inglês) como a cultura padrão.
- Arquivos JSON usados para armazenar as sequências de localização.
- Os arquivos JSON são incorporados ao assembly usando `VirtualFileSystemOptions`(consulte [sistema de arquivos virtual](Virtual-File-System.md) ).
Os arquivos JSON estão localizados na pasta do projeto "/ Localização / Recursos / Teste", como mostrado abaixo:
![localization-resource-json-files](images/localization-resource-json-files.png)
Um conteúdo do arquivo de localização JSON é mostrado abaixo:
```json
{
"culture": "en",
"texts": {
"HelloWorld": "Hello World!"
}
}
```
- Todo arquivo de localização deve definir o `culture`código para o arquivo (como "en" ou "en-US").
- `texts` A seção contém apenas a coleção de valores-chave das sequências de localização (as chaves também podem ter espaços).
### Nome Curto do Recurso de Localização
Os recursos de localização também estão disponíveis no lado do cliente (JavaScript). Portanto, definir um nome abreviado para o recurso de localização facilita o uso de textos de localização. Exemplo:
```csharp
[LocalizationResourceName("Test")]
public class TestResource
{
}
```
Consulte a seção Obtendo teste localizado / lado do cliente abaixo.
### Herdar de outros recursos
Um recurso pode herdar de outros recursos, o que possibilita reutilizar cadeias de localização existentes sem fazer referência ao recurso existente. Exemplo:
```csharp
[InheritResource(typeof(AbpValidationResource))]
public class TestResource
{
}
```
Herança alternativa configurando o `AbpLocalizationOptions`:
```csharp
services.Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<TestResource>("en") //Define the resource by "en" default culture
.AddVirtualJson("/Localization/Resources/Test") //Add strings from virtual json files
.AddBaseTypes(typeof(AbpValidationResource)); //Inherit from an existing resource
});
```
- Um recurso pode herdar de vários recursos.
- Se o novo recurso definir a mesma sequência localizada, ele substituirá a sequência.
### Estendendo o Recurso Existente
Herdar de um recurso cria um novo recurso sem modificar o existente. Em alguns casos, convém não criar um novo recurso, mas estender diretamente um recurso existente. Exemplo:
```csharp
services.Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<TestResource>()
.AddVirtualJson("/Localization/Resources/Test/Extensions");
});
```
- Se um arquivo de extensão define a mesma sequência localizada, ele substitui a sequência.
## Obtendo textos localizados
### Lado do servidor
Obter o texto localizado no lado do servidor é bastante padrão.
#### Uso mais simples de uma classe
```csharp
public class MyService
{
private readonly IStringLocalizer<TestResource> _localizer;
public MyService(IStringLocalizer<TestResource> localizer)
{
_localizer = localizer;
}
public void Foo()
{
var str = _localizer["HelloWorld"];
}
}
```
#### Uso mais simples em uma vista / página do Razor
```csharp
@inject IHtmlLocalizer<TestResource> Localizer
<h1>@Localizer["HelloWorld"]</h1>
```
Consulte a [documentação de localização da Microsoft](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) para obter detalhes sobre o uso da localização no lado do servidor.
### Lado do Cliente
A ABP fornece serviços JavaScript para usar os mesmos textos localizados no lado do cliente.
Obtenha um recurso de localização:
```js
var testResource = abp.localization.getResource('Test');
```
Localize uma sequência:
```js
var str = testResource('HelloWorld');
```

27
docs/pt-BR/Nightly-Builds.md

@ -0,0 +1,27 @@
# Compilações Noturnas
Todos os pacotes de estrutura e módulo são implantados no MyGet todas as noites durante a semana. Portanto, você pode usar ou testar o código mais recente sem aguardar o próximo lançamento.
## Configurar o Visual Studio
> Requer Visual Studio 2017 ou superior
1. Vá para `Tools > Options > NuGet Package Manager > Package Source`.
2. Clique no `+` ícone verde .
3. Defina `ABP Nightly`como *Nome* e `https://www.myget.org/F/abp-nightly/api/v3/index.json`como a *Fonte,* como mostrado abaixo: ![noite-compilação-adicionar-pepita-fonte](images/night-build-add-nuget-source.png)
4. Clique no `Update` botão
5. Clique no `OK` botão para salvar as alterações.
## Instalar pacote
Agora, você pode instalar pacotes noturnos / de visualização no seu projeto a partir do Nuget Browser ou do Package Manager Console.
![night-build-add-nuget-package](images/night-build-add-nuget-package.png)
1. No Nuget Browser, selecione "Incluir pré-lançamentos".
2. Altere a fonte do pacote para "Todos".
3. Pesquise um pacote. Você verá as pré *-liberações* do pacote formatadas como `(VERSION)-preview(DATE)`(como *v0.16.0-preview20190401* neste exemplo).
4. Você pode clicar no `Install`botão para adicionar um pacote ao seu projeto.

3
docs/pt-BR/Object-To-Object-Mapping.md

@ -0,0 +1,3 @@
## Object To Object Mapping
Façam

3
docs/pt-BR/SMS-Sending.md

@ -0,0 +1,3 @@
# Emailing
Façam!

3
docs/pt-BR/Settings.md

@ -0,0 +1,3 @@
# Settings
Façam!

3
docs/pt-BR/Specifications.md

@ -0,0 +1,3 @@
# Specifications
Façam!

275
docs/pt-BR/Startup-Templates/Application.md

@ -0,0 +1,275 @@
# Modelo de inicialização do aplicativo
## Introdução
Este modelo fornece uma estrutura de aplicativo em camadas com base nas práticas DDD ([Domain Driven Design](../Domain-Driven-Design.md)). Este documento explica a estrutura da solução e os projetos em detalhes. Se você deseja iniciar rapidamente, siga os guias abaixo:
- Consulte [Introdução ao modelo do ASP.NET Core MVC](../Getting-Started-AspNetCore-MVC-Template.md) para criar uma nova solução e executá-la para este modelo (usa o MVC como a estrutura da interface do usuário e o Entity Framework Core como o provedor de banco de dados).
- Consulte o [Tutorial de desenvolvimento de aplicativos do ASP.NET Core MVC](../Tutorials/AspNetCore-Mvc/Part-I.md) para aprender como desenvolver aplicativos usando este modelo (usa o MVC como a estrutura da interface do usuário e o Entity Framework Core como o provedor de banco de dados).
- Consulte o [Tutorial de desenvolvimento de aplicativos Angular](../Tutorials/Angular/Part-I.md) para aprender como desenvolver aplicativos usando este modelo (usa Angular como a estrutura da interface do usuário e MongoDB como o provedor de banco de dados).
## Como começar?
Você pode usar a [ABP CLI](../CLI.md) para criar um novo projeto usando este modelo de inicialização. Como alternativa, você pode criar e fazer o download diretamente na página [Introdução](https://abp.io/get-started) . A abordagem CLI é usada aqui.
Primeiro, instale a ABP CLI se você não tiver instalado antes:
```bash
dotnet tool install -g Volo.Abp.Cli
```
Em seguida, use o `abp new`comando em uma pasta vazia para criar uma nova solução:
```bash
abp new Acme.BookStore -t app
```
- `Acme.BookStore`é o nome da solução, como *YourCompany.YourProduct* . Você pode usar nomes de nível único, dois ou três níveis.
- Este exemplo especificou o nome do modelo ( `-t`ou `--template`opção). No entanto, `app`já é o modelo padrão se você não o especificar.
### Especifique a estrutura da interface do usuário
Este modelo fornece várias estruturas de interface do usuário:
- `mvc`: Interface do usuário do ASP.NET Core MVC com Razor Pages (padrão)
- `angular`: UI angular
Use `-u`ou `--ui`opção para especificar a estrutura da interface do usuário:
```bash
abp new Acme.BookStore -u angular
```
### Especifique o provedor de banco de dados
Este modelo suporta os seguintes provedores de banco de dados:
- `ef`: Entity Framework Core (padrão)
- `mongodb`: MongoDB
Use a opção `-d`(ou `--database-provider`) para especificar o provedor de banco de dados:
```bash
abp new Acme.BookStore -d mongodb
```
## Estrutura da solução
Com base nas opções especificadas, você obterá uma estrutura de solução ligeiramente diferente.
### Estrutura padrão
Se você não especificar nenhuma opção adicional, terá uma solução como a mostrada abaixo:
![livraria-visual-studio-solution-v3](../images/bookstore-visual-studio-solution-v3.png)
Os projetos são organizados em `src`e `test`pastas. `src`A pasta contém o aplicativo real que está em camadas com base nos princípios [DDD](https://docs.abp.io/en/abp/latest/Domain-Driven-Design) , como mencionado anteriormente.
O diagrama abaixo mostra as camadas e dependências do projeto do aplicativo:
![dependências de projeto em camadas](../images/layered-project-dependencies.png)
Cada seção abaixo explicará o projeto relacionado e suas dependências.
#### Projeto .Domain.Shared
Este projeto contém constantes, enumerações e outros objetos. Na verdade, eles fazem parte da camada de domínio, mas precisam ser usados por todas as camadas / projetos da solução.
Um `BookType`enum e uma `BookConsts`classe (que podem ter alguns campos constantes para a `Book`entidade, como `MaxNameLength`) são bons candidatos para este projeto.
- Este projeto não depende de outros projetos na solução. Todos os outros projetos dependem disso direta ou indiretamente.
#### .Domain Project
Essa é a camada de domínio da solução. Ele contém principalmente [entidades, raízes agregadas](../Entities.md) , [serviços de domínio](../Domain-Services.md) , [tipos de valor](../Value-Types.md) , [interfaces de repositório](../Repositories) e outros objetos de domínio.
Uma `Book`entidade, um `BookManager`serviço de domínio e uma `IBookRepository`interface são bons candidatos para este projeto.
- Depende do `.Domain.Shared`porque usa constantes, enumerações e outros objetos definidos nesse projeto.
#### .Application.Contracts Project
Este projeto contém principalmente **interfaces de** [serviço de aplicativo](../Application-Services.md) e DTO ( [Data Transfer Objects](../Data-Transfer-Objects.md) ) da camada de aplicativo. Existe para separar a interface e a implementação da camada de aplicação. Dessa forma, o projeto de interface pode ser compartilhado com os clientes como um pacote de contrato.
Uma `IBookAppService`interface e uma `BookCreationDto`classe são boas candidatas para este projeto.
- Depende do `.Domain.Shared`porque ele pode usar constantes, enumerações e outros objetos compartilhados deste projeto nas interfaces de serviço de aplicativo e DTOs.
#### Projeto de Aplicação
Este projeto contém as **implementações** de [serviço de aplicativo](../Application-Services.md) das interfaces definidas no projeto.`.Application.Contracts`
Uma `BookAppService`turma é uma boa candidata para este projeto.
- Depende do `.Application.Contracts`projeto para poder implementar as interfaces e usar os DTOs.
- Depende do `.Domain`projeto para poder usar objetos de domínio (entidades, interfaces de repositório ... etc.) para executar a lógica do aplicativo.
#### Projeto .EntityFrameworkCore
Este é o projeto de integração para o EF Core. Ele define `DbContext`e implementa as interfaces de repositório definidas no `.Domain`projeto.
- Depende do `.Domain`projeto para poder fazer referência a entidades e interfaces de repositório.
> Este projeto está disponível apenas se você estiver usando o EF Core como provedor de banco de dados. Se você selecionar outro provedor de banco de dados, seu nome será diferente.
#### Projeto .EntityFrameworkCore.DbMigrations
Contém migrações de banco de dados EF Core para a solução. Ele foi separado `DbContext`para dedicado a gerenciar migrações.
ABP é uma estrutura modular e com um design ideal, cada módulo tem sua própria `DbContext`classe. É aqui que a migração `DbContext`entra em ação e unifica todas as `DbContext`configurações em um único modelo para manter um único esquema de banco de dados. Para cenários mais avançados, você pode ter vários bancos de dados (cada um contém uma única ou algumas tabelas de módulos) e várias migrações `DbContext`(cada uma mantém um esquema de banco de dados diferente).
Observe que a migração `DbContext`é usada apenas para migrações de banco de dados e *não em tempo de execução* .
- Depende do `.EntityFrameworkCore`projeto, pois reutiliza a configuração definida para `DbContext`o aplicativo.
> Este projeto está disponível apenas se você estiver usando o EF Core como provedor de banco de dados.
#### Projeto .DbMigrator
Este é um aplicativo de console que simplifica a execução de migrações de banco de dados em ambientes de desenvolvimento e produção. Quando você executa este aplicativo, ele;
- Cria o banco de dados, se necessário.
- Aplica as migrações de banco de dados pendentes.
- Semeia os dados iniciais, se necessário.
> Este projeto possui seu próprio `appsettings.json`arquivo. Portanto, se você deseja alterar a cadeia de conexão do banco de dados, lembre-se de alterar também esse arquivo.
Especialmente, semear dados iniciais é importante neste momento. A ABP possui uma infraestrutura modular de semente de dados. Consulte [a documentação](../Data-Seeding.md) para obter mais informações sobre a propagação de dados.
Embora a criação de banco de dados e a aplicação de migrações pareça necessária apenas para bancos de dados relacionais, esse projeto ocorre mesmo que você escolha um provedor de banco de dados NoSQL (como o MongoDB). Nesse caso, ele ainda semeia os dados iniciais necessários para a aplicação.
- Depende do `.EntityFrameworkCore.DbMigrations`projeto (para EF Core), pois ele precisa acessar as migrações.
- Depende do `.Application.Contracts`projeto para poder acessar as definições de permissão, porque o semeador de dados inicial concede todas as permissões para a função de administrador por padrão.
#### Projeto .HttpApi
Este projeto é usado para definir seus controladores de API.
Na maioria das vezes, você não precisa definir manualmente os controladores de API, pois o recurso de [controladores de API automática](../AspNetCore/Auto-API-Controllers.md) da ABP os cria automaticamente, com base na sua camada de aplicação. No entanto, no caso de você precisar escrever controladores de API, este é o melhor lugar para fazê-lo.
- Depende do `.Application.Contracts`projeto para poder injetar as interfaces de serviço do aplicativo.
#### Projeto .HttpApi.Client
Este é um projeto que define os proxies do cliente C # para usar as APIs HTTP da solução. Você pode compartilhar essa biblioteca com clientes de terceiros, para que eles consumam facilmente suas APIs HTTP em seus aplicativos Dotnet (para outros tipos de aplicativos, eles ainda podem usar suas APIs, manualmente ou usando uma ferramenta em sua própria plataforma)
Na maioria das vezes, você não precisa criar proxies de clientes C # manualmente, graças ao recurso [Dynamic C # API Clients](../AspNetCore/Dynamic-CSharp-API-Clients.md) da ABP .
`.HttpApi.Client.ConsoleTestApp` project é um aplicativo de console criado para demonstrar o uso dos proxies do cliente.
- Depende do `.Application.Contracts`projeto para poder compartilhar as mesmas interfaces de serviço de aplicativo e DTOs com o serviço remoto.
> Você pode excluir este projeto e dependências se não precisar criar proxies de cliente C # para suas APIs.
#### Projeto .Web
Este projeto contém a interface do usuário (UI) do aplicativo se você estiver usando a interface do usuário do ASP.NET Core MVC. Ele contém páginas Razor, arquivos JavaScript, arquivos CSS, imagens e assim por diante ...
Este projeto contém o `appsettings.json`arquivo principal que contém a cadeia de conexão e outras configurações do aplicativo.
- Depende da `.HttpApi`camada de interface do usuário que precisa usar APIs e interfaces de serviço de aplicativo da solução.
> Se você verificar o código fonte do `.Web.csproj`arquivo, verá as referências aos `.Application`e aos `.EntityFrameworkCore.DbMigrations`projetos.
>
> Na verdade, essas referências não são necessárias durante a codificação da camada da interface do usuário, porque a camada da interface do usuário normalmente não depende da implementação do EF Core ou da camada do Aplicativo. Esses modelos de inicialização estão prontos para a implantação em camadas, em que a camada da API está hospedada em um servidor separado da camada da interface do usuário.
>
> No entanto, se você não escolher a opção `--tiered`, essas referências estarão no projeto .Web para poder hospedar as camadas da Web, API e aplicativos em um único ponto de extremidade do aplicativo.
>
> Isso permite que você use entidades e repositórios de domínio em sua camada de apresentação. No entanto, isso é considerado uma má prática de acordo com o DDD.
#### Projetos de teste
A solução possui vários projetos de teste, um para cada camada:
- `.Domain.Tests` é usado para testar a camada de domínio.
- `.Application.Tests` é usado para testar a camada de aplicativo.
- `.EntityFrameworkCore.Tests` é usado para testar a configuração do EF Core e os repositórios personalizados.
- `.Web.Tests` é usado para testar a interface do usuário (se você estiver usando a interface do ASP.NET Core MVC).
- `.TestBase` é um projeto básico (compartilhado) para todos os testes.
Além disso, `.HttpApi.Client.ConsoleTestApp`é um aplicativo de console (não um projeto de teste automatizado) que demonstra o uso de APIs HTTP de um aplicativo .NET.
Projetos de teste são preparados para testes de integração;
- É totalmente integrado à estrutura ABP e a todos os serviços em sua aplicação.
- Ele usa o banco de dados SQLite na memória para o EF Core. Para o MongoDB, ele usa a biblioteca [Mongo2Go](https://github.com/Mongo2Go/Mongo2Go) .
- A autorização está desabilitada, portanto, qualquer serviço de aplicativo pode ser facilmente usado em testes.
Você ainda pode criar testes de unidade para suas classes, que serão mais difíceis de escrever (porque você precisará preparar objetos simulados / falsos), mas mais rápidos de executar (porque apenas testa uma única classe e ignora todo o processo de inicialização).
#### Como correr?
Defina `.Web`como o projeto de inicialização e execute o aplicativo. O nome de usuário padrão é `admin`e a senha é `1q2w3E*`.
Consulte [Introdução ao modelo ASP.NET Core MVC](../Getting-Started-AspNetCore-MVC-Template.md) para obter mais informações.
### Estrutura em camadas
Se você selecionou a interface do usuário do ASP.NET Core e especificou a `--tiered`opção, a solução criada será uma solução em camadas. O objetivo da estrutura em camadas é poder **implantar aplicativos da Web e API HTTP em diferentes servidores** :
![livraria-visual-studio-solution-v3](../images/tiered-solution-servers.png)
- O navegador executa sua interface do usuário executando HTML, CSS e JavaScript.
- Os servidores da Web hospedam arquivos de interface do usuário estáticos (CSS, JavaScript, imagem ... etc.) e componentes dinâmicos (por exemplo, páginas Razor). Ele executa solicitações HTTP para o servidor da API para executar a lógica de negócios do aplicativo.
- O API Server hospeda as APIs HTTP que, em seguida, usam as camadas de aplicativo e domínio do aplicativo para executar a lógica de negócios.
- Finalmente, o servidor de banco de dados hospeda seu banco de dados.
Portanto, a solução resultante permite uma implantação em quatro camadas, comparando com a implantação em três camadas da estrutura padrão explicada anteriormente.
> A menos que você realmente precise de uma implantação em quatro camadas, é recomendável seguir a estrutura padrão que é mais simples de desenvolver, implantar e manter.
A estrutura da solução é mostrada abaixo:
![livraria-visual-studio-solution-v3](../images/bookstore-visual-studio-solution-tiered.png)
Diferente da estrutura padrão, dois novos projetos entram em jogo: `.IdentityServer`& `.HttpApi.Host`.
#### Projeto .IdentityServer
Este projeto é usado como um servidor de autenticação para outros projetos. `.Web`O projeto usa a autenticação do OpenId Connect para obter tokens de identidade e acesso para o usuário atual do IdentityServer. Em seguida, usa o token de acesso para chamar o servidor da API HTTP. O servidor HTTP API usa autenticação de token de portador para obter declarações do token de acesso para autorizar o usuário atual.
![aplicativos de solução em camadas](../images/tiered-solution-applications.png)
O ABP usa a estrutura [IdentityServer4 de](https://identityserver.io/) código aberto para a autenticação entre aplicativos. Consulte a [documentação do IdentityServer4](http://docs.identityserver.io/) para obter detalhes sobre o protocolo IdentityServer4 e OpenID Connect.
Ele possui seu próprio `appsettings.json`que contém conexão com o banco de dados e outras configurações.
#### Projeto .HttpApi.Host
Este projeto é um aplicativo que hospeda a API da solução. Ele possui seu próprio `appsettings.json`que contém conexão com o banco de dados e outras configurações.
#### Projeto .Web
Assim como a estrutura padrão, este projeto contém a interface do usuário (UI) do aplicativo. Ele contém páginas de barbear, arquivos JavaScript, arquivos de estilo, imagens e assim por diante ...
Este projeto contém um `appsettings.json`arquivo, mas desta vez não possui uma cadeia de conexão porque nunca se conecta ao banco de dados. Em vez disso, ele contém principalmente o terminal do servidor de API remoto e o servidor de autenticação.
#### Pré requisitos
- [Redis](https://redis.io/) : os aplicativos usam Redis como cache distribuído. Então, você precisa ter o Redis instalado e funcionando.
#### Como correr?
Você deve executar o aplicativo com a ordem especificada:
- Primeiro, execute o `.IdentityServer`aplicativo, pois outros aplicativos dependem dele.
- Em seguida, execute o `.HttpApi.Host`que é usado pelo `.Web`aplicativo.
- Por fim, você pode executar o `.Web`projeto e efetuar login no aplicativo (usando `admin`como nome de usuário e `1q2w3E*`senha).
### UI angular
Se você escolher Angular como a estrutura da interface do usuário (usando a `-u angular`opção), a solução será separada em duas pastas:
- `angular` A pasta contém a solução Angular UI, do lado do cliente.
- `aspnet-core` A pasta contém a solução ASP.NET Core, do lado do servidor.
O lado do servidor é muito semelhante à solução descrita acima. `.HttpApi.Host`projeto serve a API, para que o aplicativo Angular possa consumi-lo.
Os arquivos na `angular/src/environments`pasta têm a configuração essencial do aplicativo.
## Qual é o próximo?
- Consulte [Introdução ao modelo ASP.NET Core MVC](../Getting-Started-AspNetCore-MVC-Template.md) para criar uma nova solução e executá-la para este modelo.
- Consulte o [Tutorial](../Tutorials/AspNetCore-Mvc/Part-I.md) do [ASP.NET Core MVC](../Tutorials/AspNetCore-Mvc/Part-I.md) para aprender como desenvolver aplicativos usando este modelo.

7
docs/pt-BR/Startup-Templates/Index.md

@ -0,0 +1,7 @@
# Modelos de inicialização
Embora você possa começar com um projeto vazio e adicionar os pacotes necessários manualmente, os modelos de inicialização facilitam e são confortáveis para iniciar uma nova solução com a estrutura ABP. Clique no nome da lista abaixo para ver a documentação do modelo de inicialização relacionado:
- [**app**](Application.md) : modelo de aplicativo.
- [**módulo**](Module.md) : Módulo / modelo de serviço.

161
docs/pt-BR/Startup-Templates/Module.md

@ -0,0 +1,161 @@
# Modelo de inicialização do módulo MVC
Este modelo pode ser usado para criar um **módulo de aplicativo** **reutilizável com** base nas [melhores práticas e convenções de desenvolvimento do módulo](../Best-Practices/Index.md). Também é adequado para criar **microsserviços** (com ou sem interface do usuário).
## Como começar?
Você pode usar a [ABP CLI](../CLI.md) para criar um novo projeto usando este modelo de inicialização. Como alternativa, você pode criar e fazer o download diretamente na página [Introdução](https://abp.io/get-started) . A abordagem CLI é usada aqui.
Primeiro, instale a ABP CLI se você não tiver instalado antes:
```bash
dotnet tool install -g Volo.Abp.Cli
```
Em seguida, use o `abp new`comando em uma pasta vazia para criar uma nova solução:
```bash
abp new Acme.IssueManagement -t module
```
- `Acme.IssueManagement`é o nome da solução, como *YourCompany.YourProduct* . Você pode usar nomes de nível único, dois ou três níveis.
### Sem interface de usuário
O modelo vem com uma interface do usuário do MVC por padrão. Você pode usar a `--no-ui`opção para não incluir a camada da interface do usuário.
```bash
abp new Acme.IssueManagement -t mvc-module --no-ui
```
## Estrutura da solução
Com base nas opções especificadas, você obterá uma estrutura de solução ligeiramente diferente. Se você não especificar nenhuma opção, terá uma solução como a mostrada abaixo:
![issuemanagement-module-solution](../images/issuemanagement-module-solution.png)
Projetos são organizados como `src`, `test`e `host`pastas:
- `src`A pasta contém o módulo real, que é estratificado com base nos princípios [DDD](../Domain-Driven-Design.md) .
- `test` pasta contém testes de unidade e integração.
- `host`A pasta contém aplicativos com configurações diferentes para demonstrar como hospedar o módulo em um aplicativo. Isso não faz parte do módulo, mas é útil no desenvolvimento.
O diagrama abaixo mostra as camadas e dependências do projeto do módulo:
![módulo de dependências do projeto em camadas](../images/layered-project-dependencies-module.png)
Cada seção abaixo explicará o projeto relacionado e suas dependências.
### Projeto .Domain.Shared
Este projeto contém constantes, enumerações e outros objetos. Na verdade, eles fazem parte da camada de domínio, mas precisam ser usados por todas as camadas / projetos da solução.
Um `IssueType`enum e uma `IssueConsts`classe (que podem ter alguns campos constantes para a `Issue`entidade, como `MaxTitleLength`) são bons candidatos para este projeto.
- Este projeto não depende de outros projetos na solução. Todos os outros projetos dependem disso direta ou indiretamente.
### .Domain Project
Essa é a camada de domínio da solução. Ele contém principalmente [entidades, raízes agregadas](../Entities.md) , [serviços de domínio](../Domain-Services.md) , [tipos de valor](../Value-Types.md) , [interfaces de repositório](../Repositories.md) e outros objetos de domínio.
Uma `Issue`entidade, um `IssueManager`serviço de domínio e uma `IIssueRepository`interface são bons candidatos para este projeto.
- Depende do `.Domain.Shared`porque usa constantes, enumerações e outros objetos definidos nesse projeto.
### .Application.Contracts Project
Este projeto contém principalmente **interfaces de** [serviço de aplicativo](../Application-Services.md) e DTO ( [Data Transfer Objects](../Data-Transfer-Objects.md) ) da camada de aplicativo. Existe para separar a interface e a implementação da camada de aplicação. Dessa forma, o projeto de interface pode ser compartilhado com os clientes como um pacote de contrato.
Uma `IIssueAppService`interface e uma `IssueCreationDto`classe são boas candidatas para este projeto.
- Depende do `.Domain.Shared`porque ele pode usar constantes, enumerações e outros objetos compartilhados deste projeto nas interfaces de serviço de aplicativo e DTOs.
### Projeto de Aplicação
Este projeto contém as **implementações** de [serviço de aplicativo](../Application-Services.md) das interfaces definidas no projeto.`.Application.Contracts`
Uma `IssueAppService`turma é uma boa candidata para este projeto.
- Depende do `.Application.Contracts`projeto para poder implementar as interfaces e usar os DTOs.
- Depende do `.Domain`projeto para poder usar objetos de domínio (entidades, interfaces de repositório ... etc.) para executar a lógica do aplicativo.
### Projeto .EntityFrameworkCore
Este é o projeto de integração do EF Core. Ele define `DbContext`e implementa as interfaces de repositório definidas no `.Domain`projeto.
- Depende do `.Domain`projeto para poder fazer referência a entidades e interfaces de repositório.
> Você pode excluir este projeto se não desejar dar suporte ao EF Core para o seu módulo.
### Projeto .MongoDB
Este é o projeto de integração do MongoDB.
- Depende do `.Domain`projeto para poder fazer referência a entidades e interfaces de repositório.
> Você pode excluir este projeto se não quiser dar suporte ao MongoDB para o seu módulo.
### Projetos de teste
A solução possui vários projetos de teste, um para cada camada:
- `.Domain.Tests` é usado para testar a camada de domínio.
- `.Application.Tests` é usado para testar a camada de aplicativo.
- `.EntityFrameworkCore.Tests` é usado para testar a configuração do EF Core e os repositórios personalizados.
- `.MongoDB.Tests` é usado para testar a configuração do MongoDB e os repositórios personalizados.
- `.TestBase` é um projeto básico (compartilhado) para todos os testes.
Além disso, `.HttpApi.Client.ConsoleTestApp`é um aplicativo de console (não um projeto de teste automatizado) que demonstra o uso de APIs HTTP de um aplicativo Dotnet.
Projetos de teste são preparados para testes de integração;
- É totalmente integrado à estrutura ABP e a todos os serviços em sua aplicação.
- Ele usa o banco de dados SQLite na memória para o EF Core. Para o MongoDB, ele usa a biblioteca [Mongo2Go](https://github.com/Mongo2Go/Mongo2Go) .
- A autorização está desabilitada, portanto, qualquer serviço de aplicativo pode ser facilmente usado em testes.
Você ainda pode criar testes de unidade para suas classes, que serão mais difíceis de escrever (porque você precisará preparar objetos simulados / falsos), mas mais rápidos de executar (porque apenas testa uma única classe e ignora todo o processo de inicialização).
> Os testes de domínio e aplicativos estão usando o EF Core. Se você remover a integração do EF Core ou desejar usar o MongoDB para testar essas camadas, altere manualmente as referências do projeto e as dependências do módulo.
### Projetos Anfitriões
A solução possui alguns aplicativos host para executar seu módulo. Aplicativos host são usados para executar seu módulo em um aplicativo totalmente configurado. É útil no desenvolvimento. Os aplicativos host incluem alguns outros módulos além do módulo que está sendo desenvolvido:
Os aplicativos host oferecem suporte a dois tipos de cenários.
#### Cenário de aplicativo único (unificado)
Se o seu módulo tiver uma interface do usuário, o `.Web.Unified`aplicativo será usado para hospedar a interface do usuário e a API em um único ponto. Ele possui seu próprio `appsettings.json`arquivo (que inclui a cadeia de conexão do banco de dados) e as migrações do banco de dados EF Core.
Para o `.Web.Unified`aplicativo, há um único banco de dados chamado `YourProjectName_Unified`(como *IssueManagement_Unified* para esta amostra).
> Se você selecionou a `--no-ui`opção, este projeto não estará na sua solução.
##### Como correr?
Defina-o como o projeto de inicialização, execute o `Update-Database`comando para o EF Core no Package Manager Console e execute seu aplicativo. O nome de usuário padrão é `admin`e a senha é `1q2w3E*`.
#### Implantação separada e cenário de bancos de dados
Nesse cenário, há três aplicativos;
- `.IdentityServer`application é um servidor de autenticação usado por outros aplicativos. Ele possui seu próprio `appsettings.json`que contém conexão com o banco de dados e outras configurações.
- `.HttpApi.Host`hospeda a API HTTP do módulo. Ele possui seu próprio `appsettings.json`que contém conexões com o banco de dados e outras configurações.
- `.Web.Host`hospedar a interface do usuário do módulo. Este projeto contém um `appsettings.json`arquivo, mas não possui uma cadeia de conexão porque nunca se conecta ao banco de dados. Em vez disso, ele contém principalmente o terminal do servidor de API remoto e o servidor de autenticação.
O diagrama abaixo mostra a relação dos aplicativos:
![aplicativos de solução em camadas](../images/tiered-solution-applications.png)
`.Web.Host`O projeto usa a autenticação OpenId Connect para obter tokens de identidade e acesso para o usuário atual do `.IdentityServer`. Em seguida, usa o token de acesso para chamar o `.HttpApi.Host`. O servidor HTTP API usa autenticação de token de portador para obter declarações do token de acesso para autorizar o usuário atual.
##### Como correr?
Você deve executar o aplicativo com a ordem especificada:
- Primeiro, execute o `.IdentityServer`aplicativo, pois outros aplicativos dependem dele.
- Em seguida, execute o `.HttpApi.Host`que é usado pelo `.Web.Host`aplicativo.
- Por fim, você pode executar o `.Web.Host`projeto e efetuar login no aplicativo usando `admin`como nome de usuário e `1q2w3E*`senha.

3
docs/pt-BR/Testing.md

@ -0,0 +1,3 @@
# Testing
Façam!

661
docs/pt-BR/Tutorials/Angular/Part-I.md

@ -0,0 +1,661 @@
## Tutorial Angular - Parte I
### Sobre este tutorial
Nesta série de tutoriais, você criará um aplicativo usado para gerenciar uma lista de livros e seus autores. **Angular** será usado como estrutura da interface do usuário e **MongoDB** será usado como provedor de banco de dados.
Esta é a primeira parte da série de tutoriais angulares. Veja todas as peças:
- **Parte I: Crie o projeto e uma página de lista de livros (este tutorial)**
- [Parte II: Criar, atualizar e excluir livros](Part-II)
- [Parte III: Testes de Integração](Part-III)
Você pode acessar o **código fonte** do aplicativo no [repositório GitHub](https://github.com/abpframework/abp/tree/dev/samples/BookStore-Angular-MongoDb) .
### Criando o projeto
Crie um novo projeto nomeado `Acme.BookStore`selecionando Angular como a estrutura da interface do usuário e MongoDB como o provedor de banco de dados, crie o banco de dados e execute o aplicativo seguindo o [documento Introdução](../../Getting-Started-Angular-Template.md) .
### Estrutura da solução (back-end)
É assim que a estrutura da solução em camadas cuida da criação:
![solução de back-end da livraria](images/bookstore-backend-solution-v2.png)
> Você pode ver o [documento do modelo de aplicativo](../../Startup-Templates/Application.md) para entender a estrutura da solução em detalhes. No entanto, você entenderá o básico com este tutorial.
### Criar a entidade do livro
A camada de domínio no modelo de inicialização é separada em dois projetos:
- `Acme.BookStore.Domain`contém suas [entidades](../../Entities.md) , [serviços de domínio](../../Domain-Services.md) e outros objetos principais de domínio.
- `Acme.BookStore.Domain.Shared` contém constantes, enumerações ou outros objetos relacionados ao domínio que podem ser compartilhados com os clientes.
Defina [entidades](../../Entities.md) na **camada de domínio** ( `Acme.BookStore.Domain`projeto) da solução. A entidade principal do aplicativo é a `Book`. Crie uma classe, chamada `Book`, no `Acme.BookStore.Domain`projeto, como mostrado abaixo:
```csharp
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore
{
public class Book : AuditedAggregateRoot<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}
```
- O ABP possui duas classes base fundamentais para entidades: `AggregateRoot`e `Entity`. **A raiz agregada** é um dos conceitos de **DDD (Domain Driven Design)** . Consulte o [documento da entidade](../../Entities.md) para obter detalhes e melhores práticas.
- `Book`entidade herda `AuditedAggregateRoot`que adiciona algumas propriedades de auditoria ( `CreationTime`, `CreatorId`, `LastModificationTime`... etc.) no topo da `AggregateRoot`classe.
- `Guid`é o **tipo** de **chave primária** da `Book`entidade.
#### BookType Enum
Defina a `BookType`enumeração no `Acme.BookStore.Domain.Shared`projeto:
```csharp
namespace Acme.BookStore
{
public enum BookType
{
Undefined,
Adventure,
Biography,
Dystopia,
Fantastic,
Horror,
Science,
ScienceFiction,
Poetry
}
}
```
#### Adicionar entidade de livro ao seu DbContext
Adicione uma `IMongoCollection`propriedade ao `BookStoreMongoDbContext`interior do `Acme.BookStore.MongoDB`projeto:
```csharp
public class BookStoreMongoDbContext : AbpMongoDbContext
{
public IMongoCollection<Book> Books => Collection<Book>();
...
}
```
#### Adicionar dados de semente (amostra)
Esta seção é opcional, mas seria bom ter um dado inicial no banco de dados na primeira execução. O ABP fornece um [sistema de semente de dados](../../Data-Seeding.md) . Crie uma classe derivada de `IDataSeedContributor`no `.Domain`projeto:
```csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore
{
public class BookStoreDataSeederContributor
: IDataSeedContributor, ITransientDependency
{
private readonly IRepository<Book, Guid> _bookRepository;
public BookStoreDataSeederContributor(IRepository<Book, Guid> bookRepository)
{
_bookRepository = bookRepository;
}
public async Task SeedAsync(DataSeedContext context)
{
if (await _bookRepository.GetCountAsync() > 0)
{
return;
}
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
}
);
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
}
);
}
}
}
```
`BookStoreDataSeederContributor`simplesmente insere dois livros no banco de dados se não houver nenhum livro adicionado antes. O ABP descobre e executa automaticamente essa classe quando você propaga o banco de dados executando o `Acme.BookStore.DbMigrator`projeto.
### Crie o serviço de aplicativo
O próximo passo é criar um [serviço de aplicativo](../../Application-Services.md) para gerenciar (criar, listar, atualizar, excluir ...) os livros. A camada de aplicativo no modelo de inicialização é separada em dois projetos:
- `Acme.BookStore.Application.Contracts` contém principalmente seus DTOs e interfaces de serviço de aplicativo.
- `Acme.BookStore.Application` contém as implementações dos seus serviços de aplicativo.
#### BookDto
Crie uma classe DTO denominada `BookDto`no `Acme.BookStore.Application.Contracts`projeto:
```csharp
using System;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore
{
public class BookDto : AuditedEntityDto<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}
```
- **As** classes **DTO** são usadas para **transferir dados** entre a *camada de apresentação* e a *camada de aplicativo* . Consulte o [documento Objetos de transferência de dados](../../Data-Transfer-Objects.md) para obter mais detalhes.
- `BookDto` é usado para transferir dados do livro para a camada de apresentação para mostrar as informações do livro na interface do usuário.
- `BookDto`é derivado do `AuditedEntityDto<Guid>`que possui propriedades de auditoria exatamente como a `Book`classe definida acima.
Será necessário converter `Book`entidades em `BookDto`objetos enquanto retorna os livros para a camada de apresentação. A biblioteca do [AutoMapper](https://automapper.org/) pode automatizar essa conversão quando você define o mapeamento adequado. O modelo de inicialização é fornecido com o AutoMapper configurado, para que você possa definir o mapeamento na `BookStoreApplicationAutoMapperProfile`classe no `Acme.BookStore.Application`projeto:
```csharp
using AutoMapper;
namespace Acme.BookStore
{
public class BookStoreApplicationAutoMapperProfile : Profile
{
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
}
}
}
```
#### CreateUpdateBookDto
Crie uma classe DTO denominada `CreateUpdateBookDto`no `Acme.BookStore.Application.Contracts`projeto:
```csharp
using System;
using System.ComponentModel.DataAnnotations;
namespace Acme.BookStore
{
public class CreateUpdateBookDto
{
[Required]
[StringLength(128)]
public string Name { get; set; }
[Required]
public BookType Type { get; set; } = BookType.Undefined;
[Required]
public DateTime PublishDate { get; set; }
[Required]
public float Price { get; set; }
}
}
```
- Essa classe DTO é usada para obter informações do livro a partir da interface do usuário ao criar ou atualizar um livro.
- Ele define atributos de anotação de dados (como `[Required]`) para definir validações para as propriedades. Os DTOs são [validados automaticamente](../../Validation.md) pela estrutura ABP.
Em seguida, adicione um mapeamento `BookStoreApplicationAutoMapperProfile`do `CreateUpdateBookDto`objeto à `Book`entidade:
```csharp
CreateMap<CreateUpdateBookDto, Book>();
```
#### IBookAppService
Defina uma interface nomeada `IBookAppService`no `Acme.BookStore.Application.Contracts`projeto:
```csharp
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore
{
public interface IBookAppService :
ICrudAppService< //Defines CRUD methods
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting on getting a list of books
CreateUpdateBookDto, //Used to create a new book
CreateUpdateBookDto> //Used to update a book
{
}
}
```
- A definição de interfaces para serviços de aplicativos não é requerida pela estrutura. No entanto, é sugerido como uma prática recomendada.
- `ICrudAppService`define comuns **CRUD** métodos: `GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync`e `DeleteAsync`. Não é necessário estendê-lo. Em vez disso, você pode herdar da `IApplicationService`interface vazia e definir seus próprios métodos manualmente.
- Existem algumas variações de `ICrudAppService`onde você pode usar DTOs separados para cada método.
#### BookAppService
Implemente `IBookAppService`como nomeado `BookAppService`no `Acme.BookStore.Application`projeto:
```csharp
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore
{
public class BookAppService :
CrudAppService<Book, BookDto, Guid, PagedAndSortedResultRequestDto,
CreateUpdateBookDto, CreateUpdateBookDto>,
IBookAppService
{
public BookAppService(IRepository<Book, Guid> repository)
: base(repository)
{
}
}
}
```
- `BookAppService`é derivado do `CrudAppService<...>`qual implementa todos os métodos CRUD definidos acima.
- `BookAppService`injeta `IRepository<Book, Guid>`qual é o repositório padrão da `Book`entidade. O ABP cria automaticamente repositórios padrão para cada raiz (ou entidade) agregada. Veja o [documento do repositório](../../Repositories) .
- `BookAppService`usa `IObjectMapper`para converter `Book`objetos em `BookDto`objetos e `CreateUpdateBookDto`objetos em `Book`objetos. O modelo de inicialização usa a biblioteca [AutoMapper](http://automapper.org/) como o provedor de mapeamento de objetos. Você definiu os mapeamentos antes, para que funcionem conforme o esperado.
### Controladores de API automática
Você normalmente cria **controladores** para expor serviços de aplicativos como pontos de extremidade da **API HTTP** . Assim, permite que navegadores ou clientes de terceiros os chamem via AJAX. O ABP pode configurar [**automaticamente**](../../AspNetCore/Auto-API-Controllers.md) seus serviços de aplicativo como controladores de API MVC por convenção.
#### UI do Swagger
O modelo de inicialização está configurado para executar a [interface do usuário do swagger](https://swagger.io/tools/swagger-ui/) usando a biblioteca [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) . Execute o `Acme.BookStore.HttpApi.Host`aplicativo e insira `https://localhost:XXXX/swagger/`(substitua XXXX por sua própria porta) como URL no seu navegador.
Você verá alguns pontos de extremidade de serviço internos, bem como o `Book`serviço e seus pontos de extremidade no estilo REST:
![livraria-arrogância](images/bookstore-swagger-api.png)
O Swagger tem uma ótima interface para testar APIs. Você pode tentar executar a `[GET] /api/app/book`API para obter uma lista de livros.
### Crie a página de livros
Neste tutorial;
- [A CLI angular](https://angular.io/cli) será usada para criar módulos, componentes e serviços
- [NGXS](https://ngxs.gitbook.io/ngxs/) será usado como a biblioteca de gerenciamento de estado
- [O Bootstrap](https://ng-bootstrap.github.io/#/home) será usado como a biblioteca de componentes da interface do usuário.
- [O Visual Studio Code](https://code.visualstudio.com/) será usado como editor de código (você pode usar seu editor favorito).
#### Instalar pacotes NPM
Abra uma janela do terminal, vá para a `angular`pasta e execute o `yarn` comando para instalar os pacotes NPM:
```
yarn
```
#### BooksModule
Execute a seguinte linha de comando para criar um novo módulo, denominado `BooksModule`:
```bash
yarn ng generate module books --route books --module app.module
```
![Creating-Books-Module.terminal](images/bookstore-creating-books-module-terminal.png)
Execute `yarn start`, aguarde Angular para executar o aplicativo e abra `http://localhost:4200/books`em um navegador:
![página inicial dos livros](images/bookstore-initial-books-page.png)
#### Encaminhamento
Abra `app-routing.module.ts`e substitua `books`conforme mostrado abaixo:
```js
import { ApplicationLayoutComponent } from '@abp/ng.theme.basic';-
//...
{
path: 'books',
component: ApplicationLayoutComponent,
loadChildren: () => import('./books/books.module').then(m => m.BooksModule),
data: {
routes: {
name: 'Books',
} as ABP.Route,
},
},
```
`ApplicationLayoutComponent`configuração define o layout do aplicativo para a nova página. Se você deseja ver sua rota na barra de navegação (menu principal), também deve adicionar o `data`objeto com `name`propriedade à sua rota.
![página inicial dos livros](images/bookstore-initial-books-page-with-layout.png)
#### Componente da lista de livros
Primeiro, substitua pela `books.component.html`seguinte linha para colocar a saída do roteador:
```html
<router-outlet></router-outlet>
```
Em seguida, execute o comando abaixo no terminal na pasta raiz para gerar um novo componente, chamado book-list:
```bash
yarn ng generate component books/book-list
```
![terminal-criando-lista-de-livros](images/bookstore-creating-book-list-terminal.png)
Importe `SharedModule`para `BooksModule`para reutilizar alguns componentes e serviços definidos em:
```js
import { SharedModule } from '../shared/shared.module';
@NgModule({
//...
imports: [
//...
SharedModule,
],
})
export class BooksModule {}
```
Em seguida, atualize o `routes`no `books-routing.module.ts`para adicionar o novo componente book-list:
```js
import { BookListComponent } from './book-list/book-list.component';
const routes: Routes = [
{
path: '',
component: BooksComponent,
children: [{ path: '', component: BookListComponent }],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class BooksRoutingModule {}
```
![página inicial da lista de livros](images/bookstore-initial-book-list-page.png)
#### Criar BooksState
Execute o seguinte comando no terminal para criar um novo estado, denominado `BooksState`:
```shell
yarn ng generate ngxs-schematic:state books
```
Este comando cria vários novos arquivos e edições `app.modules.ts`para importar o `NgxsModule`com o novo estado:
```js
// app.module.ts
import { BooksState } from './store/states/books.state';
@NgModule({
imports: [
//...
NgxsModule.forRoot([BooksState]),
],
//...
})
export class AppModule {}
```
#### Obter dados de livros do back-end
Primeiro, crie tipos de dados para mapear os dados que retornam do back-end (você pode verificar a interface do swagger ou a API do back-end para conhecer o formato dos dados).
Modifique o `books.ts`como mostrado abaixo:
```js
export namespace Books {
export interface State {
books: Response;
}
export interface Response {
items: Book[];
totalCount: number;
}
export interface Book {
name: string;
type: BookType;
publishDate: string;
price: number;
lastModificationTime: string;
lastModifierId: string;
creationTime: string;
creatorId: string;
id: string;
}
export enum BookType {
Undefined,
Adventure,
Biography,
Dystopia,
Fantastic,
Horror,
Science,
ScienceFiction,
Poetry,
}
}
```
Adicionada `Book`interface que representa um objeto de livro e `BookType`enum representa uma categoria de livro.
#### BooksService
Agora, crie um novo serviço, nomeado `BooksService`para executar chamadas HTTP para o servidor:
```bash
yarn ng generate service books/shared/books
```
![serviço-terminal-saída](images/bookstore-service-terminal-output.png)
Modifique `books.service.ts`como mostrado abaixo:
```js
import { Injectable } from '@angular/core';
import { RestService } from '@abp/ng.core';
import { Books } from '../../store/models';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class BooksService {
constructor(private restService: RestService) {}
get(): Observable<Books.Response> {
return this.restService.request<void, Books.Response>({
method: 'GET',
url: '/api/app/book'
});
}
}
```
Adicionado o `get`método para obter a lista de livros executando uma solicitação HTTP no terminal relacionado.
Substitua o `books.actions.ts`conteúdo conforme mostrado abaixo:
```js
export class GetBooks {
static readonly type = '[Books] Get';
}
```
#### Implementar o BooksState
Abra o `books.state.ts`e altere o arquivo, como mostrado abaixo:
```js
import { State, Action, StateContext, Selector } from '@ngxs/store';
import { GetBooks } from '../actions/books.actions';
import { Books } from '../models/books';
import { BooksService } from '../../books/shared/books.service';
import { tap } from 'rxjs/operators';
@State<Books.State>({
name: 'BooksState',
defaults: { books: {} } as Books.State,
})
export class BooksState {
@Selector()
static getBooks(state: Books.State) {
return state.books.items || [];
}
constructor(private booksService: BooksService) {}
@Action(GetBooks)
get(ctx: StateContext<Books.State>) {
return this.booksService.get().pipe(
tap(booksResponse => {
ctx.patchState({
books: booksResponse,
});
}),
);
}
}
```
Adicionada a `GetBooks`ação que usa o `BookService`definido acima para obter os livros e corrigir o estado.
> O NGXS exige retornar o observável sem assiná-lo, conforme feito nesta amostra (na função get).
#### BookListComponent
Modifique o `book-list.component.ts`como mostrado abaixo:
```js
import { Component, OnInit } from '@angular/core';
import { Store, Select } from '@ngxs/store';
import { BooksState } from '../../store/states';
import { Observable } from 'rxjs';
import { Books } from '../../store/models';
import { GetBooks } from '../../store/actions';
@Component({
selector: 'app-book-list',
templateUrl: './book-list.component.html',
styleUrls: ['./book-list.component.scss'],
})
export class BookListComponent implements OnInit {
@Select(BooksState.getBooks)
books$: Observable<Books.Book[]>;
booksType = Books.BookType;
loading = false;
constructor(private store: Store) {}
ngOnInit() {
this.loading = true;
this.store.dispatch(new GetBooks()).subscribe(() => {
this.loading = false;
});
}
}
```
> Consulte as [ações de despacho](https://ngxs.gitbook.io/ngxs/concepts/store#dispatching-actions) e [selecione](https://ngxs.gitbook.io/ngxs/concepts/select) na documentação do NGXS para obter mais informações sobre esses recursos do NGXS.
Substitua o `book-list.component.html`conteúdo conforme mostrado abaixo:
```html
<div id="wrapper" class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
Books
</h5>
</div>
</div>
</div>
<div class="card-body">
<p-table [value]="books$ | async" [loading]="loading" [paginator]="true" [rows]="10">
<ng-template pTemplate="header">
<tr>
<th>Book name</th>
<th>Book type</th>
<th>Publish date</th>
<th>Price</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-data>
<tr>
<td>{{ data.name }}</td>
<td>{{ booksType[data.type] }}</td>
<td>{{ data.publishDate | date }}</td>
<td>{{ data.price }}</td>
</tr>
</ng-template>
</p-table>
</div>
</div>
```
> Usamos a [tabela PrimeNG](https://www.primefaces.org/primeng/#/table) neste componente.
A página de livros resultante é mostrada abaixo:
![livraria-lista-de-livros](images/bookstore-book-list.png)
E esta é a estrutura de pastas e arquivos no final deste tutorial:
![img](images/bookstore-angular-file-tree.png)
> Este tutorial segue o [Guia de estilo angular](https://angular.io/guide/styleguide#file-tree) .
### Próxima parte
Veja a [próxima parte](Part-II.md) deste tutorial.

582
docs/pt-BR/Tutorials/Angular/Part-II.md

@ -0,0 +1,582 @@
## Tutorial Angular - Parte II
### Sobre este tutorial
Esta é a segunda parte da série de tutoriais angulares. Veja todas as peças:
- [Parte I: Crie o projeto e uma página da lista de livros](Part-I.md)
- **Parte II: Criar, atualizar e excluir livros (este tutorial)**
- [Parte III: Testes de Integração](Part-III.md)
Você pode acessar o **código fonte** do aplicativo no [repositório GitHub](https://github.com/abpframework/abp/tree/dev/samples/BookStore-Angular-MongoDb) .
### Criando um novo livro
Nesta seção, você aprenderá como criar um novo formulário de diálogo modal para criar um novo livro.
#### Definição do tipo
Criar uma interface, com o nome `CreateUpdateBookInput`no `books.ts`como mostrado abaixo:
```js
export namespace Books {
//...
export interface CreateUpdateBookInput {
name: string;
type: BookType;
publishDate: string;
price: number;
}
}
```
`CreateUpdateBookInput`interface corresponde ao `CreateUpdateBookDto`no back-end.
#### Método de Serviço
Abra o `books.service.ts`e adicione um novo método, nomeado `create`para executar uma solicitação HTTP POST no servidor:
```js
create(createBookInput: Books.CreateUpdateBookInput): Observable<Books.Book> {
return this.restService.request<Books.CreateUpdateBookInput, Books.Book>({
method: 'POST',
url: '/api/app/book',
body: createBookInput
});
}
```
- `restService.request`A função obtém parâmetros genéricos para os tipos enviados e recebidos do servidor. Este exemplo envia um `CreateUpdateBookInput`objeto e recebe um `Book`objeto (você pode definir o tipo `void`de solicitação ou retorno, se não for usado).
#### Definições de estado
Adicione a `CreateUpdateBook`ação ao `books.actions.ts`conforme mostrado abaixo:
```js
import { Books } from '../models';
export class CreateUpdateBook {
static readonly type = '[Books] Create Update Book';
constructor(public payload: Books.CreateUpdateBookInput) {}
}
```
Abra `books.state.ts`e defina o `save`método que ouvirá uma `CreateUpdateBook`ação para criar um livro:
```js
import { ... , CreateUpdateBook } from '../actions/books.actions';
import { ... , switchMap } from 'rxjs/operators';
//...
@Action(CreateUpdateBook)
save(ctx: StateContext<Books.State>, action: CreateUpdateBook) {
return this.booksService
.create(action.payload)
.pipe(switchMap(() => ctx.dispatch(new GetBooks())));
}
```
Quando a `SaveBook`ação é despachada, o método save é executado. Ele chama o `create`método do `BooksService`definido anteriormente. Após a chamada de serviço, `BooksState`despacha a `GetBooks`ação para obter livros novamente do servidor para atualizar a página.
#### Adicionar um modal ao BookListComponent
Abra o `book-list.component.html`e adicione o `abp-modal`para mostrar / ocultar o modal para criar um novo livro.
```html
<abp-modal [(visible)]="isModalOpen">
<ng-template #abpHeader>
<h3>New Book</h3>
</ng-template>
<ng-template #abpBody> </ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" #abpClose>
Cancel
</button>
</ng-template>
</abp-modal>
```
`abp-modal`é um componente pré-construído para mostrar os modais. Embora você possa usar outra abordagem para mostrar um modal, `abp-modal`fornece benefícios adicionais.
Adicione um botão rotulado `New book`para mostrar o modal:
```html
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
Books
</h5>
</div>
<div class="text-right col col-md-6">
<button id="create-role" class="btn btn-primary" type="button" (click)="createBook()">
<i class="fa fa-plus mr-1"></i> <span>New book</span>
</button>
</div>
</div>
```
Abra a variável `book-list.component.ts`e adicione `isModalOpen`e `createBook`método para mostrar / ocultar o modal.
```js
isModalOpen = false;
//...
createBook() {
this.isModalOpen = true;
}
```
![modal vazio](images/bookstore-empty-new-book-modal.png)
#### Criar um formulário reativo
> [Os formulários reativos](https://angular.io/guide/reactive-forms) fornecem uma abordagem orientada a modelo para lidar com entradas de formulário cujos valores mudam ao longo do tempo.
Adicione uma `form`variável e injete um `FormBuilder`serviço `book-list.component.ts`como mostrado abaixo (lembre-se de adicionar a instrução de importação).
```js
import { FormGroup, FormBuilder } from '@angular/forms';
form: FormGroup;
constructor(
//...
private fb: FormBuilder
) {}
```
> O serviço [FormBuilder](https://angular.io/api/forms/FormBuilder) fornece métodos convenientes para gerar controles. Reduz a quantidade de clichê necessária para criar formulários complexos.
Adicione o `buildForm`método para criar um formulário de livro.
```js
buildForm() {
this.form = this.fb.group({
name: ['', Validators.required],
type: [null, Validators.required],
publishDate: [null, Validators.required],
price: [null, Validators.required],
});
}
```
- O `group`método de `FormBuilder`( `fb`) cria a `FormGroup`.
- Adicionado `Validators.required`método estático que valida o elemento de formulário relacionado.
Modifique o `createBook`método como mostrado abaixo:
```js
createBook() {
this.buildForm();
this.isModalOpen = true;
}
```
#### Crie os elementos DOM do formulário
Abra `book-list.component.html`e adicione o formulário no modelo de corpo do modal.
```html
<ng-template #abpBody>
<form [formGroup]="form">
<div class="form-group">
<label for="book-name">Name</label><span> * </span>
<input type="text" id="book-name" class="form-control" formControlName="name" autofocus />
</div>
<div class="form-group">
<label for="book-price">Price</label><span> * </span>
<input type="number" id="book-price" class="form-control" formControlName="price" />
</div>
<div class="form-group">
<label for="book-type">Type</label><span> * </span>
<select class="form-control" id="book-type" formControlName="type">
<option [ngValue]="null">Select a book type</option>
<option [ngValue]="booksType[type]" *ngFor="let type of bookTypeArr"> {{ type }}</option>
</select>
</div>
<div class="form-group">
<label>Publish date</label><span> * </span>
<input
#datepicker="ngbDatepicker"
class="form-control"
name="datepicker"
formControlName="publishDate"
ngbDatepicker
(click)="datepicker.toggle()"
/>
</div>
</form>
</ng-template>
```
- Este modelo cria um formulário com os campos Nome, Preço, Tipo e Data de publicação.
> Usamos o [datepicker do NgBootstrap](https://ng-bootstrap.github.io/#/components/datepicker/overview) neste componente.
Abra o `book-list.component.ts`e crie uma matriz chamada `bookTypeArr`:
```js
//...
form: FormGroup;
bookTypeArr = Object.keys(Books.BookType).filter(
bookType => typeof this.booksType[bookType] === 'number'
);
```
O `bookTypeArr`contém os campos da `BookType`enumeração. A matriz resultante é mostrada abaixo:
```js
['Adventure', 'Biography', 'Dystopia', 'Fantastic' ...]
```
Essa matriz foi usada no modelo de formulário anterior (no `ngFor`loop).
#### Requisitos do Datepicker
Você precisa importar `NgbDatepickerModule`para o `books.module.ts`:
```js
import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap';
@NgModule({
imports: [
// ...
NgbDatepickerModule,
],
})
export class BooksModule {}
```
Abra o `book-list.component.ts`e adicione `providers`como mostrado abaixo:
```js
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
@Component({
// ...
providers: [{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }],
})
export class BookListComponent implements OnInit {
// ...
```
> O `NgbDateAdapter`valor do Datepicker converte em `Date`tipo. Consulte os [adaptadores datepicker](https://ng-bootstrap.github.io/#/components/datepicker/overview) para obter mais detalhes.
![forma de livro novo](images/bookstore-new-book-form.png)
#### Salvando o livro
Abra o `book-list.component.html`e adicione um `abp-button`para salvar o formulário.
```html
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" #abpClose>
Cancel
</button>
<button class="btn btn-primary" (click)="save()">
<i class="fa fa-check mr-1"></i>
Save
</button>
</ng-template>
```
Isso adiciona um botão Salvar à área inferior do modal:
![livraria-novo-livro-formulário-v2](images/bookstore-new-book-form-v2.png)
Em seguida, defina um `save`método no `BookListComponent`:
```js
save() {
if (this.form.invalid) {
return;
}
this.store.dispatch(new CreateUpdateBook(this.form.value)).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
});
}
```
### Atualizando um livro existente
#### BooksService
Abra o `books.service.ts`e adicione os métodos `getById`e `update`.
```js
getById(id: string): Observable<Books.Book> {
return this.restService.request<void, Books.Book>({
method: 'GET',
url: `/api/app/book/${id}`
});
}
update(updateBookInput: Books.CreateUpdateBookInput, id: string): Observable<Books.Book> {
return this.restService.request<Books.CreateUpdateBookInput, Books.Book>({
method: 'PUT',
url: `/api/app/book/${id}`,
body: updateBookInput
});
}
```
#### Ação CreateUpdateBook
Abra o parâmetro `books.actins.ts`e adicione `id`à `CreateUpdateBook`ação:
```js
export class CreateUpdateBook {
static readonly type = '[Books] Create Update Book';
constructor(public payload: Books.CreateUpdateBookInput, public id?: string) {}
}
```
Abra `books.state.ts`e modifique o `save`método conforme mostrado abaixo:
```js
@Action(CreateUpdateBook)
save(ctx: StateContext<Books.State>, action: CreateUpdateBook) {
let request;
if (action.id) {
request = this.booksService.update(action.payload, action.id);
} else {
request = this.booksService.create(action.payload);
}
return request.pipe(switchMap(() => ctx.dispatch(new GetBooks())));
}
```
#### BookListComponent
Injectar `BooksService`dependência, adicionando-o ao `book-list.component.ts`construtor e adicione uma variável chamada `selectedBook`.
```js
import { BooksService } from '../shared/books.service';
//...
selectedBook = {} as Books.Book;
constructor(
//...
private booksService: BooksService
)
```
`booksService`é usado para obter o livro de edição para preparar o formulário. Modifique o `buildForm`método para reutilizar o mesmo formulário ao editar um livro.
```js
buildForm() {
this.form = this.fb.group({
name: [this.selectedBook.name || '', Validators.required],
type: this.selectedBook.type || null,
publishDate: this.selectedBook.publishDate ? new Date(this.selectedBook.publishDate) : null,
price: this.selectedBook.price || null,
});
}
```
Adicione o `editBook`método como mostrado abaixo:
```js
editBook(id: string) {
this.booksService.getById(id).subscribe(book => {
this.selectedBook = book;
this.buildForm();
this.isModalOpen = true;
});
}
```
Adicionado `editBook`método para obter o livro de edição, criar o formulário e mostrar o modal.
Agora, adicione a `selectedBook`definição ao `createBook`método para reutilizar o mesmo formulário ao criar um novo livro:
```js
createBook() {
this.selectedBook = {} as Books.Book;
//...
}
```
Modifique o `save`método para passar o ID do livro selecionado, como mostrado abaixo:
```js
save() {
if (this.form.invalid) {
return;
}
this.store.dispatch(new CreateUpdateBook(this.form.value, this.selectedBook.id))
.subscribe(() => {
this.isModalOpen = false;
this.form.reset();
});
}
```
#### Adicione o menu suspenso "Ações" à tabela
Abra o `book-list.component.html` e adicione modifique o `p-table` como mostrado abaixo:
```html
<p-table [value]="books$ | async" [loading]="loading" [paginator]="true" [rows]="10">
<ng-template pTemplate="header">
<tr>
<th>Actions</th>
<th>Book name</th>
<th>Book type</th>
<th>Publish date</th>
<th>Price</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-data>
<tr>
<td>
<div ngbDropdown class="d-inline-block">
<button
class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
ngbDropdownToggle
>
<i class="fa fa-cog mr-1"></i>Actions
</button>
<div ngbDropdownMenu>
<button ngbDropdownItem (click)="editBook(data.id)">Edit</button>
</div>
</div>
</td>
<td>{{ data.name }}</td>
<td>{{ booksType[data.type] }}</td>
<td>{{ data.publishDate | date }}</td>
<td>{{ data.price }}</td>
</tr>
</ng-template>
</p-table>
```
- Adicionado um `th`para a coluna "Ações".
- Adicionado `button`com `ngbDropdownToggle`para abrir ações quando clicamos no botão.
> Nós costumávamos usar o [NgbDropdown](https://ng-bootstrap.github.io/#/components/dropdown/examples) no menu suspenso de ações.
A interface do usuário final é semelhante a:
![botões de ações](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/Angular/images/bookstore-actions-buttons.png)
Atualize o cabeçalho modal para alterar o título com base na operação atual:
```html
<ng-template #abpHeader>
<h3>{{ selectedBook.id ? 'Edit' : 'New Book' }}</h3>
</ng-template>
```
![botões de ações](images/bookstore-edit-modal.png)
### Exclusão de um livro existente
#### BooksService
Abra `books.service.ts`e inclua um `delete`método para excluir um livro com o `id`, executando uma solicitação HTTP no nó de extremidade relacionado:
```js
delete(id: string): Observable<void> {
return this.restService.request<void, void>({
method: 'DELETE',
url: `/api/app/book/${id}`
});
}
```
#### Ação DeleteBook
Adicione uma ação chamada `DeleteBook`para `books.actions.ts`:
```js
export class DeleteBook {
static readonly type = '[Books] Delete';
constructor(public id: string) {}
}
```
Abra o `books.state.ts`e adicione o `delete`método que ouvirá a `DeleteBook`ação para excluir um livro:
```js
import { ... , DeleteBook } from '../actions/books.actions';
//...
@Action(DeleteBook)
delete(ctx: StateContext<Books.State>, action: DeleteBook) {
return this.booksService.delete(action.id).pipe(switchMap(() => ctx.dispatch(new GetBooks())));
}
```
- Adicionado `DeleteBook`à lista de importação.
- Usa `bookService`para excluir o livro.
\#### Adicionar um botão Excluir
Abra `book-list.component.html`e modifique `ngbDropdownMenu`para adicionar o botão excluir, como mostrado abaixo:
```html
<div ngbDropdownMenu>
...
<button ngbDropdownItem (click)="delete(data.id, data.name)">
Delete
</button>
</div>
```
A interface do usuário suspensa de ações finais é semelhante a abaixo:
![livraria-final-ações-suspensa](images/bookstore-final-actions-dropdown.png)
\#### Caixa de diálogo Excluir confirmação
Abra `book-list.component.ts`e injete o `ConfirmationService`.
```js
import { ConfirmationService } from '@abp/ng.theme.shared';
//...
constructor(
//...
private confirmationService: ConfirmationService
)
```
> `ConfirmationService` é um serviço simples fornecido pela estrutura ABP que usa internamente o PrimeNG.
Adicione um método de exclusão ao `BookListComponent`:
```js
import { ... , DeleteBook } from '../../store/actions';
import { ... , Toaster } from '@abp/ng.theme.shared';
//...
delete(id: string, name: string) {
this.confirmationService
.error(`${name} will be deleted. Do you confirm that?`, 'Are you sure?')
.subscribe(status => {
if (status === Toaster.Status.confirm) {
this.store.dispatch(new DeleteBook(id));
}
});
}
```
O `delete`método mostra um pop-up de confirmação e assina a resposta do usuário. `DeleteBook`ação despachada somente se o usuário clicar no `Yes`botão O pop-up de confirmação é exibido abaixo:
![livraria-confirmação-pop-up](images/bookstore-confirmation-popup.png)
### Próxima parte
Veja a [próxima parte](Part-III.md) deste tutorial.

181
docs/pt-BR/Tutorials/Angular/Part-III.md

@ -0,0 +1,181 @@
## Tutorial do ASP.NET Core MVC - Parte III
### Sobre este tutorial
Esta é a terceira parte da série de tutoriais Angular. Veja todas as peças:
- [Parte I: Crie o projeto e uma página da lista de livros](Part-I.md)
- [Parte II: Criar, atualizar e excluir livros](Part-II.md)
- **Parte III: Testes de Integração (este tutorial)**
Esta parte abrange os testes do **lado** do **servidor** . Você pode acessar o **código fonte** do aplicativo no [repositório GitHub](https://github.com/abpframework/abp/tree/dev/samples/BookStore-Angular-MongoDb) .
### Testar projetos na solução
Existem vários projetos de teste na solução:
![livraria-teste-projetos](images/bookstore-test-projects-v3.png)
Cada projeto é usado para testar o projeto de aplicativo relacionado. Os projetos de teste usam as seguintes bibliotecas para teste:
- [xunit](https://xunit.github.io/) como a principal estrutura de teste.
- [Shouldly](http://shouldly.readthedocs.io/en/latest/) como uma biblioteca de asserções.
- [NSubstitute](http://nsubstitute.github.io/) como uma biblioteca de zombaria.
### Adicionando dados de teste
O modelo de inicialização contém a `BookStoreTestDataSeedContributor`classe no `Acme.BookStore.TestBase`projeto que cria alguns dados para executar os testes.
Mude a `BookStoreTestDataSeedContributor`classe como mostrado abaixo:
```csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Guids;
namespace Acme.BookStore
{
public class BookStoreTestDataSeedContributor
: IDataSeedContributor, ITransientDependency
{
private readonly IRepository<Book, Guid> _bookRepository;
private readonly IGuidGenerator _guidGenerator;
public BookStoreTestDataSeedContributor(
IRepository<Book, Guid> bookRepository,
IGuidGenerator guidGenerator)
{
_bookRepository = bookRepository;
_guidGenerator = guidGenerator;
}
public async Task SeedAsync(DataSeedContext context)
{
await _bookRepository.InsertAsync(
new Book
{
Id = _guidGenerator.Create(),
Name = "Test book 1",
Type = BookType.Fantastic,
PublishDate = new DateTime(2015, 05, 24),
Price = 21
}
);
await _bookRepository.InsertAsync(
new Book
{
Id = _guidGenerator.Create(),
Name = "Test book 2",
Type = BookType.Science,
PublishDate = new DateTime(2014, 02, 11),
Price = 15
}
);
}
}
}
```
- Injetado `IRepository<Book, Guid>`e usado no `SeedAsync`para criar duas entidades de livro como dados de teste.
- `IGuidGenerator`Serviço usado para criar GUIDs. Embora `Guid.NewGuid()`funcionasse perfeitamente para testes, `IGuidGenerator`possui recursos adicionais especialmente importantes ao usar bancos de dados reais (consulte o documento de geração do [Guid](../../Guid-Generation.md) para obter mais informações).
### Testando o BookAppService
Crie uma classe de teste denominada `BookAppService_Tests`no `Acme.BookStore.Application.Tests`projeto:
```csharp
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Xunit;
namespace Acme.BookStore
{
public class BookAppService_Tests : BookStoreApplicationTestBase
{
private readonly IBookAppService _bookAppService;
public BookAppService_Tests()
{
_bookAppService = GetRequiredService<IBookAppService>();
}
[Fact]
public async Task Should_Get_List_Of_Books()
{
//Act
var result = await _bookAppService.GetListAsync(
new PagedAndSortedResultRequestDto()
);
//Assert
result.TotalCount.ShouldBeGreaterThan(0);
result.Items.ShouldContain(b => b.Name == "Test book 1");
}
}
}
```
- `Should_Get_List_Of_Books`O teste simplesmente usa o `BookAppService.GetListAsync`método para obter e verificar a lista de usuários.
Adicione um novo teste que crie um novo livro válido:
```csharp
[Fact]
public async Task Should_Create_A_Valid_Book()
{
//Act
var result = await _bookAppService.CreateAsync(
new CreateUpdateBookDto
{
Name = "New test book 42",
Price = 10,
PublishDate = DateTime.Now,
Type = BookType.ScienceFiction
}
);
//Assert
result.Id.ShouldNotBe(Guid.Empty);
result.Name.ShouldBe("New test book 42");
}
```
Adicione um novo teste que tente criar um livro inválido e falhe:
```csharp
[Fact]
public async Task Should_Not_Create_A_Book_Without_Name()
{
var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
{
await _bookAppService.CreateAsync(
new CreateUpdateBookDto
{
Name = "",
Price = 10,
PublishDate = DateTime.Now,
Type = BookType.ScienceFiction
}
);
});
exception.ValidationErrors
.ShouldContain(err => err.MemberNames.Any(mem => mem == "Name"));
}
```
- Como o `Name`está vazio, o ABP lança um `AbpValidationException`.
Abra a **janela Test Explorer** (use o menu Test -> Windows -> Test Explorer, se não estiver visível) e **execute Todos os** testes:
![testes de serviço de livraria](images/bookstore-test-explorer.png)
Parabéns, ícones verdes mostram que os testes foram aprovados com sucesso!

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-actions-buttons.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-angular-file-tree.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-backend-solution-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-book-list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-confirmation-popup.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-creating-book-list-terminal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-creating-books-module-terminal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-edit-modal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-empty-new-book-modal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-final-actions-dropdown.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-initial-book-list-page.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-initial-books-page-with-layout.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-initial-books-page.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-new-book-form-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-new-book-form.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-service-terminal-output.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-swagger-api.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-test-explorer.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
docs/pt-BR/Tutorials/Angular/images/bookstore-test-projects-v3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

462
docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-I.md

@ -0,0 +1,462 @@
## Tutorial do ASP.NET Core MVC - Parte I
### Sobre este tutorial
Nesta série de tutoriais, você criará um aplicativo usado para gerenciar uma lista de livros e seus autores. **O Entity Framework Core** (EF Core) será usado como o provedor ORM, pois é o provedor de banco de dados padrão.
Esta é a primeira parte da série de tutoriais do ASP.NET Core MVC. Veja todas as peças:
- **Parte I: Crie o projeto e uma página de lista de livros (este tutorial)**
- [Parte II: Criar, atualizar e excluir livros](Part-II.md)
- [Parte III: Testes de Integração](Part-III.md)
Você pode acessar o **código fonte** do aplicativo [no repositório GitHub](https://github.com/abpframework/abp/tree/master/samples/BookStore) .
> Você também pode assistir a [este curso em vídeo](https://amazingsolutions.teachable.com/p/lets-build-the-bookstore-application) preparado por um membro da comunidade ABP, com base neste tutorial.
### Criando o projeto
Crie um novo projeto chamado `Acme.BookStore`, crie o banco de dados e execute o aplicativo seguindo o [documento Introdução](Getting-Started-AspNetCore-MVC-Template.md).
### Estrutura da solução
É assim que a estrutura da solução em camadas cuida da criação:
![livraria-visual-studio-solução](images/bookstore-visual-studio-solution-v3.png)
> Você pode ver o [documento do modelo de aplicativo](https://docs.abp.io/en/abp/latest/Startup-Templates/Application) para entender a estrutura da solução em detalhes. No entanto, você entenderá o básico com este tutorial.
### Criar a entidade do livro
A camada de domínio no modelo de inicialização é separada em dois projetos:
- `Acme.BookStore.Domain`contém suas [entidades](https://docs.abp.io/en/abp/latest/Entities.md) , [serviços de domínio](https://docs.abp.io/en/abp/latest/Domain-Services) e outros objetos principais de domínio.
- `Acme.BookStore.Domain.Shared` contém constantes, enumerações ou outros objetos relacionados ao domínio que podem ser compartilhados com os clientes.
Defina [entidades](https://docs.abp.io/en/abp/latest/Entities) na **camada de domínio** ( `Acme.BookStore.Domain`projeto) da solução. A entidade principal do aplicativo é a `Book`. Crie uma classe, chamada `Book`, no `Acme.BookStore.Domain`projeto, como mostrado abaixo:
```csharp
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore
{
public class Book : AuditedAggregateRoot<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}
```
- O ABP possui duas classes base fundamentais para entidades: `AggregateRoot`e `Entity`. **A raiz agregada** é um dos conceitos de **DDD (Domain Driven Design)** . Consulte o [documento da entidade](https://docs.abp.io/en/abp/latest/Entities) para obter detalhes e melhores práticas.
- `Book`entidade herda `AuditedAggregateRoot`que adiciona algumas propriedades de auditoria ( `CreationTime`, `CreatorId`, `LastModificationTime`... etc.) no topo da `AggregateRoot`classe.
- `Guid`é o **tipo** de **chave primária** da `Book`entidade.
#### BookType Enum
Defina a `BookType`enumeração no `Acme.BookStore.Domain.Shared`projeto:
```csharp
namespace Acme.BookStore
{
public enum BookType
{
Undefined,
Adventure,
Biography,
Dystopia,
Fantastic,
Horror,
Science,
ScienceFiction,
Poetry
}
}
```
#### Adicionar entidade de livro ao seu DbContext
O EF Core exige que você relacione entidades com seu DbContext. A maneira mais fácil de fazer isso é adicionar uma `DbSet`propriedade à `BookStoreDbContext`classe no `Acme.BookStore.EntityFrameworkCore`projeto, conforme mostrado abaixo:
```csharp
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
public DbSet<Book> Books { get; set; }
...
}
```
#### Configure sua entidade do livro
Abra o `BookStoreDbContextModelCreatingExtensions.cs`arquivo no `Acme.BookStore.EntityFrameworkCore`projeto e adicione o seguinte código ao final do `ConfigureBookStore`método para configurar a entidade Livro:
```csharp
builder.Entity<Book>(b =>
{
b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
});
```
#### Adicionar nova migração e atualizar o banco de dados
O modelo de inicialização usa [as primeiras migrações do código principal EF](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/) para criar e manter o esquema do banco de dados. Abra o **Gerenciador de Console Package (PMC)** (sob as *Ferramentas / Gerente Nuget Package* menu), selecione o `Acme.BookStore.EntityFrameworkCore.DbMigrations`como o **projeto padrão** e execute o seguinte comando:
![livraria-pmc-add-book-migration](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration-v2.png)
Isso criará uma nova classe de migração dentro da `Migrations`pasta. Em seguida, execute o `Update-Database`comando para atualizar o esquema do banco de dados:
```
PM> Update-Database
```
#### Adicionar dados de amostra
`Update-Database`O comando criou a `AppBooks`tabela no banco de dados. Abra seu banco de dados e insira algumas linhas de amostra, para que você possa mostrá-las na página:
![livraria-livros-mesa](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-books-table.png)
### Crie o serviço de aplicativo
O próximo passo é criar um [serviço de aplicativo](https://docs.abp.io/en/abp/latest/Application-Services) para gerenciar (criar, listar, atualizar, excluir ...) os livros. A camada de aplicativo no modelo de inicialização é separada em dois projetos:
- `Acme.BookStore.Application.Contracts` contém principalmente seus DTOs e interfaces de serviço de aplicativo.
- `Acme.BookStore.Application` contém as implementações dos seus serviços de aplicativo.
#### BookDto
Crie uma classe DTO denominada `BookDto`no `Acme.BookStore.Application.Contracts`projeto:
```csharp
using System;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore
{
public class BookDto : AuditedEntityDto<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}
```
- **As** classes **DTO** são usadas para **transferir dados** entre a *camada de apresentação* e a *camada de aplicativo* . Consulte o [documento Objetos de transferência de dados](https://docs.abp.io/en/abp/latest/Data-Transfer-Objects) para obter mais detalhes.
- `BookDto` é usado para transferir dados do livro para a camada de apresentação para mostrar as informações do livro na interface do usuário.
- `BookDto`é derivado do `AuditedEntityDto<Guid>`que possui propriedades de auditoria exatamente como a `Book`classe definida acima.
Será necessário converter `Book`entidades em `BookDto`objetos enquanto retorna os livros para a camada de apresentação. [A](https://automapper.org/) biblioteca do [AutoMapper](https://automapper.org/) pode automatizar essa conversão quando você define o mapeamento adequado. O modelo de inicialização é fornecido com o AutoMapper configurado, para que você possa definir o mapeamento na `BookStoreApplicationAutoMapperProfile`classe no `Acme.BookStore.Application`projeto:
```csharp
using AutoMapper;
namespace Acme.BookStore
{
public class BookStoreApplicationAutoMapperProfile : Profile
{
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
}
}
}
```
#### CreateUpdateBookDto
Crie uma classe DTO denominada `CreateUpdateBookDto`no `Acme.BookStore.Application.Contracts`projeto:
```csharp
using System;
using System.ComponentModel.DataAnnotations;
namespace Acme.BookStore
{
public class CreateUpdateBookDto
{
[Required]
[StringLength(128)]
public string Name { get; set; }
[Required]
public BookType Type { get; set; } = BookType.Undefined;
[Required]
public DateTime PublishDate { get; set; }
[Required]
public float Price { get; set; }
}
}
```
- Essa classe DTO é usada para obter informações do livro a partir da interface do usuário ao criar ou atualizar um livro.
- Ele define atributos de anotação de dados (como `[Required]`) para definir validações para as propriedades. Os DTOs são [validados automaticamente](https://docs.abp.io/en/abp/latest/Validation) pela estrutura ABP.
Em seguida, adicione um mapeamento `BookStoreApplicationAutoMapperProfile`do `CreateUpdateBookDto`objeto à `Book`entidade:
```csharp
CreateMap<CreateUpdateBookDto, Book>();
```
#### IBookAppService
Defina uma interface nomeada `IBookAppService`no `Acme.BookStore.Application.Contracts`projeto:
```csharp
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore
{
public interface IBookAppService :
ICrudAppService< //Defines CRUD methods
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting on getting a list of books
CreateUpdateBookDto, //Used to create a new book
CreateUpdateBookDto> //Used to update a book
{
}
}
```
- A definição de interfaces para serviços de aplicativos não é requerida pela estrutura. No entanto, é sugerido como uma prática recomendada.
- `ICrudAppService`define comuns **CRUD** métodos: `GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync`e `DeleteAsync`. Não é necessário estendê-lo. Em vez disso, você pode herdar da `IApplicationService`interface vazia e definir seus próprios métodos manualmente.
- Existem algumas variações de `ICrudAppService`onde você pode usar DTOs separados para cada método.
#### BookAppService
Implemente `IBookAppService`como nomeado `BookAppService`no `Acme.BookStore.Application`projeto:
```csharp
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore
{
public class BookAppService :
CrudAppService<Book, BookDto, Guid, PagedAndSortedResultRequestDto,
CreateUpdateBookDto, CreateUpdateBookDto>,
IBookAppService
{
public BookAppService(IRepository<Book, Guid> repository)
: base(repository)
{
}
}
}
```
- `BookAppService`é derivado do `CrudAppService<...>`qual implementa todos os métodos CRUD definidos acima.
- `BookAppService`injeta `IRepository<Book, Guid>`qual é o repositório padrão da `Book`entidade. O ABP cria automaticamente repositórios padrão para cada raiz (ou entidade) agregada. Veja o [documento](https://docs.abp.io/en/abp/latest/Repositories) do [repositório](https://docs.abp.io/en/abp/latest/Repositories) .
- `BookAppService`usa `IObjectMapper`para converter `Book`objetos em `BookDto`objetos e `CreateUpdateBookDto`objetos em `Book`objetos. O modelo de inicialização usa a biblioteca [AutoMapper](http://automapper.org/) como o provedor de mapeamento de objetos. Você definiu os mapeamentos antes, para que funcionem conforme o esperado.
### Controladores de API automática
Você normalmente cria **controladores** para expor serviços de aplicativos como pontos de extremidade da **API HTTP** . Assim, permite que navegadores ou clientes de terceiros os chamem via AJAX. O ABP pode configurar [**automaticamente**](https://docs.abp.io/en/abp/latest/AspNetCore/Auto-API-Controllers) seus serviços de aplicativo como controladores de API MVC por convenção.
#### UI do Swagger
O modelo de inicialização está configurado para executar a [interface do usuário](https://swagger.io/tools/swagger-ui/) do [swagger](https://swagger.io/tools/swagger-ui/) usando a biblioteca [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) . Execute o aplicativo e insira `https://localhost:XXXX/swagger/`(substitua XXXX por sua própria porta) como URL no seu navegador.
Você verá alguns pontos de extremidade de serviço internos, bem como o `Book`serviço e seus pontos de extremidade no estilo REST:
![livraria-arrogância](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-swagger.png)
O Swagger tem uma ótima interface para testar APIs. Você pode tentar executar a `[GET] /api/app/book`API para obter uma lista de livros.
### Proxies dinâmicos de JavaScript
É comum chamar pontos de extremidade da API HTTP via AJAX do lado do **JavaScript** . Você pode usar `$.ajax`ou outra ferramenta para chamar os pontos de extremidade. No entanto, o ABP oferece uma maneira melhor.
O ABP cria **dinamicamente** **proxies** JavaScript para todos os pontos de extremidade da API. Portanto, você pode usar qualquer **terminal,** assim como chamar uma **função JavaScript** .
#### Testando no console do desenvolvedor do navegador
Você pode testar facilmente os proxies JavaScript usando o **Console** do **desenvolvedor** do seu navegador favorito agora. Execute o aplicativo, abra as **ferramentas de desenvolvedor** do navegador (atalho: F12), vá para a guia **Console** , digite o seguinte código e pressione enter:
```js
acme.bookStore.book.getList({}).done(function (result) { console.log(result); });
```
- `acme.bookStore`é o espaço para nome do `BookAppService`convertido em [camelCase](https://en.wikipedia.org/wiki/Camel_case) .
- `book`é o nome convencional para o `BookAppService`(postfix do AppService removido e convertido em camelCase).
- `getList`é o nome convencional para o `GetListAsync`método definido na `AsyncCrudAppService`classe base (postfix assíncrono removido e convertido em camelCase).
- `{}`O argumento é usado para enviar um objeto vazio ao `GetListAsync`método que normalmente espera um objeto do tipo `PagedAndSortedResultRequestDto`usado para enviar opções de paginação e classificação ao servidor (todas as propriedades são opcionais, para que você possa enviar um objeto vazio).
- `getList`A função retorna a `promise`. Portanto, você pode passar um retorno de chamada para a função `done`(ou `then`) para obter o resultado do servidor.
A execução desse código produz a seguinte saída:
![livraria-teste-js-proxy-getlist](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-test-js-proxy-getlist.png)
Você pode ver a **lista de livros** retornada do servidor. Você também pode verificar a guia de **rede** das ferramentas do desenvolvedor para ver a comunicação do cliente com o servidor:
![livraria-teste-js-proxy-getlist-rede](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-test-js-proxy-getlist-network.png)
Vamos **criar um novo livro** usando a `create`função:
```js
acme.bookStore.book.create({ name: 'Foundation', type: 7, publishDate: '1951-05-24', price: 21.5 }).done(function (result) { console.log('successfully created the book with id: ' + result.id); });
```
Você deve ver uma mensagem no console, algo assim:
```
successfully created the book with id: f3f03580-c1aa-d6a9-072d-39e75c69f5c7
```
Verifique a `Books`tabela no banco de dados para ver a nova linha do livro. Você pode tentar `get`, `update`e `delete`funciona mesmo.
### Crie a página de livros
É hora de criar algo visível e utilizável! Em vez do MVC clássico, usaremos a nova abordagem de [interface do usuário do Razor Pages,](https://docs.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/razor-pages-start) recomendada pela Microsoft.
Crie uma nova `Books`pasta na `Pages`pasta do `Acme.BookStore.Web`projeto e adicione uma nova página Razor denominada `Index.cshtml`:
![livraria-add-index-page](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page-v2.png)
Abra `Index.cshtml`e altere o conteúdo, como mostrado abaixo:
```html
@page
@using Acme.BookStore.Web.Pages.Books
@inherits Acme.BookStore.Web.Pages.BookStorePage
@model IndexModel
<h2>Books</h2>
```
- Esse código altera a herança padrão do Razor View Page Model para que ele **herda** da `BookStorePage`classe (em vez de `PageModel`). A `BookStorePage`classe que acompanha o modelo de inicialização e fornece algumas propriedades / métodos compartilhados usados por todas as páginas.
- Verifique se o `IndexModel`( *Index.cshtml.cs)* possui o `Acme.BookStore.Pages.Books`espaço para nome ou atualize-o no `Index.cshtml`.
#### Adicionar página de livros ao menu principal
Abra a `BookStoreMenuContributor`classe na `Menus`pasta e adicione o seguinte código ao final do `ConfigureMainMenuAsync`método:
```csharp
context.Menu.AddItem(
new ApplicationMenuItem("BooksStore", l["Menu:BookStore"])
.AddItem(new ApplicationMenuItem("BooksStore.Books", l["Menu:Books"], url: "/Books"))
);
```
#### Localizando os itens de menu
Os textos de localização estão localizados na `Localization/BookStore`pasta do `Acme.BookStore.Domain.Shared`projeto:
![arquivos de localização de livraria](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files-v2.png)
Abra o `en.json`arquivo e adicione textos de localização `Menu:BookStore`e `Menu:Books`chaves ao final do arquivo:
```json
{
"culture": "en",
"texts": {
"Menu:BookStore": "Book Store",
"Menu:Books": "Books"
}
}
```
- O sistema de localização da ABP é construído no sistema de [localização padrão do ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) e o estende de várias maneiras. Consulte o [documento de localização](https://docs.abp.io/en/abp/latest/Localization) para obter detalhes.
- Os nomes das chaves de localização são arbitrários. Você pode definir qualquer nome. Preferimos adicionar `Menu:`prefixo aos itens de menu para distinguir de outros textos. Se um texto não estiver definido no arquivo de localização, ele **recuará** para a chave de localização (comportamento padrão do ASP.NET Core).
Execute o aplicativo e veja se o novo item de menu foi adicionado à barra superior:
![itens-menu-livraria](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-menu-items.png)
Quando você clica no item de menu Livros, você é redirecionado para a nova página Livros.
#### Lista de livros
Usaremos o plug-in [Datatables.net](https://datatables.net/) JQuery para mostrar a lista de tabelas na página. As tabelas de dados podem funcionar completamente via AJAX, são rápidas e oferecem uma boa experiência ao usuário. O plug-in Datatables está configurado no modelo de inicialização, para que você possa usá-lo diretamente em qualquer página sem incluir nenhum estilo ou arquivo de script em sua página.
##### Index.cshtml
Altere o `Pages/Books/Index.cshtml`seguinte:
```html
@page
@inherits Acme.BookStore.Web.Pages.BookStorePage
@model Acme.BookStore.Web.Pages.Books.IndexModel
@section scripts
{
<abp-script src="/Pages/Books/index.js" />
}
<abp-card>
<abp-card-header>
<h2>@L["Books"]</h2>
</abp-card-header>
<abp-card-body>
<abp-table striped-rows="true" id="BooksTable">
<thead>
<tr>
<th>@L["Name"]</th>
<th>@L["Type"]</th>
<th>@L["PublishDate"]</th>
<th>@L["Price"]</th>
<th>@L["CreationTime"]</th>
</tr>
</thead>
</abp-table>
</abp-card-body>
</abp-card>
```
- `abp-script` [O auxiliar de marca](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro) é usado para adicionar **scripts** externos à página. Possui muitos recursos adicionais em comparação com a `script`tag padrão . Ele lida com **minificação** e **controle** de **versão,** por exemplo. Consulte o [documento de compactação e redução](https://docs.abp.io/en/abp/latest/AspNetCore/Bundling-Minification) para obter detalhes.
- `abp-card`e `abp-table`são **auxiliares de tags** para o [componente de cartão](http://getbootstrap.com/docs/4.1/components/card/) do Twitter Bootstrap . Existem muitos auxiliares de tag no ABP para usar facilmente a maioria dos componentes de [autoinicialização](https://getbootstrap.com/) . Você também pode usar tags HTML regulares em vez desses auxiliares de tag, mas o uso de tag reduz o código HTML e evita erros com a ajuda do intellisense e da verificação do tipo de tempo de compilação. Consulte o [documento auxiliares](https://docs.abp.io/en/abp/latest/AspNetCore/Tag-Helpers) da [tag](https://docs.abp.io/en/abp/latest/AspNetCore/Tag-Helpers) .
- Você pode **localizar** os nomes das colunas no arquivo de localização, como fez nos itens de menu acima.
##### Adicionar um arquivo de script
Crie um `index.js`arquivo JavaScript na `Pages/Books/`pasta:
![arquivo-index-js-bookstore](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file-v2.png)
`index.js` o conteúdo é mostrado abaixo:
```js
$(function () {
var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({
ajax: abp.libs.datatables.createAjax(acme.bookStore.book.getList),
columnDefs: [
{ data: "name" },
{ data: "type" },
{ data: "publishDate" },
{ data: "price" },
{ data: "creationTime" }
]
}));
});
```
- `abp.libs.datatables.createAjax` é uma função auxiliar para adaptar os proxies dinâmicos da API JavaScript da ABP ao formato do Datatable.
- `abp.libs.datatables.normalizeConfiguration`é outra função auxiliar. Não há necessidade de usá-lo, mas simplifica a configuração das tabelas de dados, fornecendo valores convencionais para as opções ausentes.
- `acme.bookStore.book.getList` é a função para obter a lista de livros (você já viu isso antes).
- Consulte [a documentação do Datatable](https://datatables.net/manual/) para obter mais opções de configuração.
A interface do usuário final é mostrada abaixo:
![livraria-lista-de-livros](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-book-list-2.png)
### Próxima parte
Veja a [próxima parte](https://docs.abp.io/en/abp/latest/Tutorials/AspNetCore-Mvc/Part-II) deste tutorial.

466
docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-II.md

@ -0,0 +1,466 @@
## Tutorial do ASP.NET Core MVC - Parte II
### Sobre este tutorial
Esta é a segunda parte da série de tutoriais do ASP.NET Core MVC. Veja todas as peças:
- [Parte I: Crie o projeto e uma página da lista de livros](https://docs.abp.io/en/abp/latest/Tutorials/AspNetCore-Mvc/Part-I)
- **Parte II: Criar, atualizar e excluir livros (este tutorial)**
- [Parte III: Testes de Integração](https://docs.abp.io/en/abp/latest/Tutorials/AspNetCore-Mvc/Part-III)
Você pode acessar o **código fonte** do aplicativo [no repositório GitHub](https://github.com/volosoft/abp/tree/master/samples/BookStore) .
> Você também pode assistir a [este curso em vídeo](https://amazingsolutions.teachable.com/p/lets-build-the-bookstore-application) preparado por um membro da comunidade ABP, com base neste tutorial.
### Criando um novo livro
Nesta seção, você aprenderá como criar um novo formulário de diálogo modal para criar um novo livro. A caixa de diálogo do resultado será assim:
![livraria-criar-diálogo](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-create-dialog-2.png)
#### Crie o formulário modal
Crie uma nova página de navalha, nomeada `CreateModal.cshtml`sob a `Pages/Books`pasta do `Acme.BookStore.Web`projeto:
![livraria-adicionar-criar-diálogo](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog-v2.png)
##### CreateModal.cshtml.cs
Abra o `CreateModal.cshtml.cs`arquivo ( `CreateModalModel`classe) e substitua pelo seguinte código:
```csharp
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Acme.BookStore.Web.Pages.Books
{
public class CreateModalModel : BookStorePageModel
{
[BindProperty]
public CreateUpdateBookDto Book { get; set; }
private readonly IBookAppService _bookAppService;
public CreateModalModel(IBookAppService bookAppService)
{
_bookAppService = bookAppService;
}
public async Task<IActionResult> OnPostAsync()
{
await _bookAppService.CreateAsync(Book);
return NoContent();
}
}
}
```
- Esta classe é derivada do em `BookStorePageModel`vez do padrão `PageModel`. `BookStorePageModel`herda o `PageModel`e adiciona algumas propriedades / métodos comuns que podem ser usados pelas classes de modelo de página.
- `[BindProperty]`O atributo na `Book`propriedade vincula os dados de solicitação posterior a essa propriedade.
- Essa classe simplesmente injeta o `IBookAppService`em seu construtor e chama o `CreateAsync`método no `OnPostAsync`manipulador.
##### CreateModal.cshtml
Abra o `CreateModal.cshtml`arquivo e cole o código abaixo:
```html
@page
@inherits Acme.BookStore.Web.Pages.BookStorePage
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model Acme.BookStore.Web.Pages.Books.CreateModalModel
@{
Layout = null;
}
<abp-dynamic-form abp-model="Book" data-ajaxForm="true" asp-page="/Books/CreateModal">
<abp-modal>
<abp-modal-header title="@L["NewBook"].Value"></abp-modal-header>
<abp-modal-body>
<abp-form-content />
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
</abp-modal>
</abp-dynamic-form>
```
- Este modal usa o
```
abp-dynamic-form
```
auxiliar de marca para criar automaticamente o formulário a partir da
```
CreateBookViewModel
```
classe.
- `abp-model`O atributo indica o objeto do modelo, a `Book`propriedade neste caso.
- `data-ajaxForm` O atributo faz com que o formulário seja enviado via AJAX, em vez de uma postagem de página clássica.
- `abp-form-content`O auxiliar de marca é um espaço reservado para renderizar os controles do formulário (isso é opcional e necessário apenas se você tiver adicionado outro conteúdo à `abp-dynamic-form`marca, como nesta página).
#### Adicione o botão "Novo livro"
Abra `Pages/Books/Index.cshtml`e altere a `abp-card-header`tag, como mostrado abaixo:
```html
<abp-card-header>
<abp-row>
<abp-column size-md="_6">
<h2>@L["Books"]</h2>
</abp-column>
<abp-column size-md="_6" class="text-right">
<abp-button id="NewBookButton"
text="@L["NewBook"].Value"
icon="plus"
button-type="Primary" />
</abp-column>
</abp-row>
</abp-card-header>
```
Acabei de adicionar um botão **Novo livro** no canto **superior direito** da tabela:
![livraria-novo-livro-botão](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-new-book-button.png)
Abra o `pages/books/index.js`e adicione o seguinte código logo após a configuração da tabela de dados:
```js
var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');
createModal.onResult(function () {
dataTable.ajax.reload();
});
$('#NewBookButton').click(function (e) {
e.preventDefault();
createModal.open();
});
```
- `abp.ModalManager`é uma classe auxiliar para abrir e gerenciar modais no lado do cliente. Ele usa internamente o modal padrão do Twitter Bootstrap, mas abstrai muitos detalhes, fornecendo uma API simples.
Agora, você pode **executar o aplicativo** e adicionar novos livros usando o novo formulário modal.
### Atualizando um livro existente
Crie uma nova página de navalha, nomeada `EditModal.cshtml`sob a `Pages/Books`pasta do `Acme.BookStore.Web`projeto:
![livraria-adicionar-editar-diálogo](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-edit-dialog.png)
#### EditModal.cshtml.cs
Abra o `EditModal.cshtml.cs`arquivo ( `EditModalModel`classe) e substitua pelo seguinte código:
```csharp
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Acme.BookStore.Web.Pages.Books
{
public class EditModalModel : BookStorePageModel
{
[HiddenInput]
[BindProperty(SupportsGet = true)]
public Guid Id { get; set; }
[BindProperty]
public CreateUpdateBookDto Book { get; set; }
private readonly IBookAppService _bookAppService;
public EditModalModel(IBookAppService bookAppService)
{
_bookAppService = bookAppService;
}
public async Task OnGetAsync()
{
var bookDto = await _bookAppService.GetAsync(Id);
Book = ObjectMapper.Map<BookDto, CreateUpdateBookDto>(bookDto);
}
public async Task<IActionResult> OnPostAsync()
{
await _bookAppService.UpdateAsync(Id, Book);
return NoContent();
}
}
}
```
- `[HiddenInput]`e `[BindProperty]`são atributos padrão do ASP.NET Core MVC. Utilizado `SupportsGet`para obter o valor do ID a partir do parâmetro da string de consulta da solicitação.
- Mapeado `BookDto`(recebido de `BookAppService.GetAsync`) para `CreateUpdateBookDto`no `GetAsync`método
- O `OnPostAsync`simplesmente usa `BookAppService.UpdateAsync`para atualizar a entidade.
#### Mapeamento de BookDto para CreateUpdateBookDto
A fim de executar `BookDto`a `CreateUpdateBookDto`opor mapeamento, abrir o `BookStoreWebAutoMapperProfile.cs`no `Acme.BookStore.Web`projecto e alterá-lo como se mostra abaixo:
```csharp
using AutoMapper;
namespace Acme.BookStore.Web
{
public class BookStoreWebAutoMapperProfile : Profile
{
public BookStoreWebAutoMapperProfile()
{
CreateMap<BookDto, CreateUpdateBookDto>();
}
}
}
```
- Apenas adicionado `CreateMap<BookDto, CreateUpdateBookDto>();`como a definição de mapeamento.
#### EditModal.cshtml
Substitua o `EditModal.cshtml`conteúdo pelo seguinte:
```html
@page
@inherits Acme.BookStore.Web.Pages.BookStorePage
@using Acme.BookStore.Web.Pages.Books
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model EditModalModel
@{
Layout = null;
}
<abp-dynamic-form abp-model="Book" data-ajaxForm="true" asp-page="/Books/EditModal">
<abp-modal>
<abp-modal-header title="@L["Update"].Value"></abp-modal-header>
<abp-modal-body>
<abp-input asp-for="Id" />
<abp-form-content />
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
</abp-modal>
</abp-dynamic-form>
```
Esta página é muito semelhante à `CreateModal.cshtml`exceção;
- Ele inclui um `abp-input`para a `Id`propriedade armazenar o ID do livro de edição (que é uma entrada oculta).
- Ele usa `Books/EditModal`como URL de postagem e texto de *atualização* como cabeçalho modal.
#### Adicione o menu suspenso "Ações" à tabela
Adicionaremos um botão suspenso ("Ações") para cada linha da tabela. A interface do usuário final é assim:
![livraria-livros-mesa-ações](https://raw.githubusercontent.com/abpframework/abp/master/docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-books-table-actions.png)
Abra a `Pages/Books/Index.cshtml`página e altere a seção da tabela como mostrado abaixo:
```html
<abp-table striped-rows="true" id="BooksTable">
<thead>
<tr>
<th>@L["Actions"]</th>
<th>@L["Name"]</th>
<th>@L["Type"]</th>
<th>@L["PublishDate"]</th>
<th>@L["Price"]</th>
<th>@L["CreationTime"]</th>
</tr>
</thead>
</abp-table>
```
- Acabei de adicionar uma nova `th`tag para as "Ações".
Abra `pages/books/index.js`e substitua o conteúdo como abaixo:
```js
$(function () {
var l = abp.localization.getResource('BookStore');
var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');
var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal');
var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({
processing: true,
serverSide: true,
paging: true,
searching: false,
autoWidth: false,
scrollCollapse: true,
order: [[1, "asc"]],
ajax: abp.libs.datatables.createAjax(acme.bookStore.book.getList),
columnDefs: [
{
rowAction: {
items:
[
{
text: l('Edit'),
action: function (data) {
editModal.open({ id: data.record.id });
}
}
]
}
},
{ data: "name" },
{ data: "type" },
{ data: "publishDate" },
{ data: "price" },
{ data: "creationTime" }
]
}));
createModal.onResult(function () {
dataTable.ajax.reload();
});
editModal.onResult(function () {
dataTable.ajax.reload();
});
$('#NewBookButton').click(function (e) {
e.preventDefault();
createModal.open();
});
});
```
- Utilizado `abp.localization.getResource('BookStore')`para poder usar os mesmos textos de localização definidos no lado do servidor.
- Adicionado um novo `ModalManager`nome `createModal`para abrir a caixa de diálogo criar modal.
- Adicionado um novo `ModalManager`nome `editModal`para abrir a caixa de diálogo modal de edição.
- Adicionada uma nova coluna no início da `columnDefs`seção. Esta coluna é usada para o botão suspenso "Ações".
- A ação "Novo livro" simplesmente chama `createModal.open`para abrir a caixa de diálogo Criar.
- A ação "Editar" simplesmente chama `editModal.open`para abrir a caixa de diálogo de edição. `Você pode executar o aplicativo e editar qualquer livro selecionando a ação de edição.
### Exclusão de um livro existente
Abra o `pages/books/index.js`e adicione um novo item ao `rowAction` `items`:
```js
{
text: l('Delete'),
confirmMessage: function (data) {
return l('BookDeletionConfirmationMessage', data.record.name);
},
action: function (data) {
acme.bookStore.book
.delete(data.record.id)
.then(function() {
abp.notify.info(l('SuccessfullyDeleted'));
dataTable.ajax.reload();
});
}
}
```
- `confirmMessage`A opção é usada para fazer uma pergunta de confirmação antes de executar o `action`.
- Utilizou a `acme.bookStore.book.delete`função de proxy javascript para executar uma solicitação AJAX para excluir um livro.
- `abp.notify.info` é usado para mostrar uma notificação toastr logo após a exclusão.
O `index.js`conteúdo final é mostrado abaixo:
```js
$(function () {
var l = abp.localization.getResource('BookStore');
var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');
var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal');
var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({
processing: true,
serverSide: true,
paging: true,
searching: false,
autoWidth: false,
scrollCollapse: true,
order: [[1, "asc"]],
ajax: abp.libs.datatables.createAjax(acme.bookStore.book.getList),
columnDefs: [
{
rowAction: {
items:
[
{
text: l('Edit'),
action: function (data) {
editModal.open({ id: data.record.id });
}
},
{
text: l('Delete'),
confirmMessage: function (data) {
return l('BookDeletionConfirmationMessage', data.record.name);
},
action: function (data) {
acme.bookStore.book
.delete(data.record.id)
.then(function() {
abp.notify.info(l('SuccessfullyDeleted'));
dataTable.ajax.reload();
});
}
}
]
}
},
{ data: "name" },
{ data: "type" },
{ data: "publishDate" },
{ data: "price" },
{ data: "creationTime" }
]
}));
createModal.onResult(function () {
dataTable.ajax.reload();
});
editModal.onResult(function () {
dataTable.ajax.reload();
});
$('#NewBookButton').click(function (e) {
e.preventDefault();
createModal.open();
});
});
```
Abra o `en.json`no `Acme.BookStore.Domain.Shared`projeto e adicione a seguinte linha:
```json
"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?"
```
Execute o aplicativo e tente excluir um livro.
### Próxima parte
Veja a [próxima parte](https://docs.abp.io/en/abp/latest/Tutorials/AspNetCore-Mvc/Part-III) deste tutorial.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save