Browse Source

Merge branch 'master' into pr/1170

pull/1267/head
Halil İbrahim Kalkan 7 years ago
parent
commit
f59ad3d192
  1. 3
      .gitignore
  2. 19
      README.md
  3. 30
      docs/cs/Index.md
  4. 292
      docs/cs/docs-nav.json
  5. 19
      docs/docs-langs.json
  6. 6
      docs/en/AspNetCore/Auto-API-Controllers.md
  7. 3
      docs/en/AspNetCore/Tag-Helpers.md
  8. 3
      docs/en/AspNetCore/Tag-Helpers/Dynamic-Forms.md
  9. 0
      docs/en/AspNetCore/Tag-Helpers/Index.md
  10. 3
      docs/en/Aspect-Oriented-Programming.md
  11. 137
      docs/en/CLI.md
  12. 3
      docs/en/Caching.md
  13. 38
      docs/en/Contribution/Localization-Text-Files.md
  14. 3
      docs/en/CorrelationId.md
  15. 3
      docs/en/Data-Filtering.md
  16. 3
      docs/en/Data-Seeding.md
  17. 3
      docs/en/Distributed-Event-Bus.md
  18. 3
      docs/en/Extension-Methods-And-Helpers.md
  19. 77
      docs/en/Getting-Started-AspNetCore-MVC-Template.md
  20. 2
      docs/en/Index.md
  21. 3
      docs/en/Integration-Tests.md
  22. 3
      docs/en/JavaScript/Dynamic-JavaScript-API-Clients.md
  23. 3
      docs/en/Local-Event-Bus.md
  24. 3
      docs/en/SMS-Sending.md
  25. 3
      docs/en/Settings.md
  26. 3
      docs/en/Specifications.md
  27. 11
      docs/en/Startup-Templates/Index.md
  28. 160
      docs/en/Startup-Templates/Mvc-Module.md
  29. 260
      docs/en/Startup-Templates/Mvc.md
  30. 3
      docs/en/Testing.md
  31. 147
      docs/en/Tutorials/AspNetCore-Mvc/Part-I.md
  32. 68
      docs/en/Tutorials/AspNetCore-Mvc/Part-II.md
  33. 87
      docs/en/Tutorials/AspNetCore-Mvc/Part-III.md
  34. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog-v2.png
  35. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog.png
  36. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page-v2.png
  37. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page.png
  38. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-appservice-tests.png
  39. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file-v2.png
  40. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file.png
  41. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files-v2.png
  42. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files.png
  43. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-test-projects-v2.png
  44. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-test-projects.png
  45. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v2.png
  46. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v3.png
  47. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution.png
  48. 3
      docs/en/Value-Objects.md
  49. 6
      docs/en/docs-nav.json
  50. BIN
      docs/en/images/bookstore-user-management-v2.png
  51. BIN
      docs/en/images/bookstore-user-management.png
  52. BIN
      docs/en/images/bookstore-visual-studio-solution-tiered.png
  53. BIN
      docs/en/images/bookstore-visual-studio-solution-v2.png
  54. BIN
      docs/en/images/bookstore-visual-studio-solution-v3.png
  55. BIN
      docs/en/images/bookstore-visual-studio-solution.png
  56. BIN
      docs/en/images/db-migrator-app.png
  57. BIN
      docs/en/images/disable-package-restore-visual-studio.png
  58. BIN
      docs/en/images/issuemanagement-module-solution.png
  59. BIN
      docs/en/images/layered-project-dependencies-module.png
  60. BIN
      docs/en/images/layered-project-dependencies.png
  61. BIN
      docs/en/images/tiered-solution-applications.png
  62. BIN
      docs/en/images/tiered-solution-servers.png
  63. 6
      docs/zh-Hans/AspNetCore/Auto-API-Controllers.md
  64. 136
      docs/zh-Hans/CLI.md
  65. 38
      docs/zh-Hans/Contribution/Localization-Text-Files.md
  66. 3
      docs/zh-Hans/Data-Seeding.md
  67. 3
      docs/zh-Hans/Dynamic-JavaScript-API-Clients.md
  68. 71
      docs/zh-Hans/Getting-Started-AspNetCore-MVC-Template.md
  69. 2
      docs/zh-Hans/Getting-Started-Console-Application.md
  70. 92
      docs/zh-Hans/Index.md
  71. 8
      docs/zh-Hans/Startup-Templates/Index.md
  72. 6
      docs/zh-Hans/Startup-Templates/Mvc-Module.md
  73. 259
      docs/zh-Hans/Startup-Templates/Mvc.md
  74. 142
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md
  75. 66
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md
  76. 89
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md
  77. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog-v2.png
  78. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog.png
  79. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page-v2.png
  80. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page.png
  81. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-appservice-tests.png
  82. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file-v2.png
  83. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file.png
  84. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files-v2.png
  85. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files.png
  86. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-test-projects-v2.png
  87. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-test-projects.png
  88. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v2.png
  89. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v3.png
  90. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution.png
  91. 3
      docs/zh-Hans/Value-Objects.md
  92. 4
      docs/zh-Hans/docs-nav.json
  93. BIN
      docs/zh-Hans/images/bookstore-user-management-v2.png
  94. BIN
      docs/zh-Hans/images/bookstore-user-management.png
  95. BIN
      docs/zh-Hans/images/bookstore-visual-studio-solution-tiered.png
  96. BIN
      docs/zh-Hans/images/bookstore-visual-studio-solution-v2.png
  97. BIN
      docs/zh-Hans/images/bookstore-visual-studio-solution-v3.png
  98. BIN
      docs/zh-Hans/images/bookstore-visual-studio-solution.png
  99. BIN
      docs/zh-Hans/images/db-migrator-app.png
  100. BIN
      docs/zh-Hans/images/disable-package-restore-visual-studio.png

3
.gitignore

@ -23,7 +23,7 @@ bld/
[Ll]og/ [Ll]og/
# Visual Studio 2015 cache/options directory # Visual Studio 2015 cache/options directory
.vs/ **/.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot # Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/ #wwwroot/
@ -268,7 +268,6 @@ modules/blog/app/Volo.BlogTestApp/Logs/*.*
modules/blogging/app/Volo.BloggingTestApp/Logs/*.* modules/blogging/app/Volo.BloggingTestApp/Logs/*.*
modules/blogging/app/Volo.BloggingTestApp/wwwroot/files/*.* modules/blogging/app/Volo.BloggingTestApp/wwwroot/files/*.*
modules/docs/app/VoloDocs.Web/Logs/*.* modules/docs/app/VoloDocs.Web/Logs/*.*
samples/BookStore/src/Acme.BookStore.Web/Logs/*.*
templates/module/app/MyCompanyName.MyProjectName.DemoApp/Logs/*.* templates/module/app/MyCompanyName.MyProjectName.DemoApp/Logs/*.*
templates/mvc/src/MyCompanyName.MyProjectName.Web/Logs/*.* templates/mvc/src/MyCompanyName.MyProjectName.Web/Logs/*.*

19
README.md

@ -8,36 +8,25 @@ See the official [web site (abp.io)](https://abp.io/) for more information.
### Status ### Status
This project is in **very early preview** stage and it's not suggested to use it in a real project. This project is in **preview** stage and it's not suggested to use it in production yet.
### Documentation ### Documentation
See the <a href="https://abp.io/documents/" target="_blank">documentation</a>. See the <a href="https://abp.io/documents/" target="_blank">documentation</a>.
### How to Build
- Run the `build-all.ps1`. It will build all the solutions in this repository.
### Development ### Development
#### Pre Requirements #### Pre Requirements
- Visual Studio 2017 15.9.0+ - Visual Studio 2019 16.1.0+
#### Framework #### Framework
Framework solution is located under the `framework` folder. It has no external dependency. Just open `Volo.Abp.sln` by Visual Studio and start the development. Framework solution is located under the `framework` folder. It has no external dependency.
#### Modules/Templates #### Modules/Templates
[Modules](modules/) and [Templates](templates/) have their own solutions and have **local references** to the framework. Unfortunately, Visual Studio has some problems with local references to projects those are out of the solution. As a workaround, you should follow the steps below in order to start developing a module/template: [Modules](modules/) and [Templates](templates/) have their own solutions and have **local references** to the framework and each other.
- Disable "*Automatically check for missing packages during build in Visual Studio*" in the Visual Studio options.
![disable-package-restore-visual-studio](docs/en/images/disable-package-restore-visual-studio.png)
- When you open a solution, first run `dotnet restore` in the root folder of the solution.
- When you change a dependency of a project (or any of the dependencies of your projects change their dependencies), run `dotnet restore` again.
### Contribution ### Contribution

30
docs/cs/Index.md

@ -0,0 +1,30 @@
# ABP dokumentace
ABP je **open source aplikační framework** se zaměřením na vývoj webových aplikací založených na ASP.NET Core, zároveň ho však lze využít i k vývoji jiných typů aplikací.
K procházení dokumentace využijte navigační nabídky vlevo.
## Stav projektu
ABP je **novou generací** open source frameworku [ASP.NET Boilerplate](https://aspnetboilerplate.com/). V současné době je v ranné fázi a není připraven k ostrému nasazení. Na dokumentaci se stále pracuje a ještě zdaleka není dokončena.
Pro aplikace na krátkodobé a ostré nasazení je doporučeno použít [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework, který je bohatý na funkce, vyspělý, aktivně udržovaný a aktuální.
## Začínáme
Nejsnazší cestou jak začít nový projekt s ABP je užití startovací šablony:
* [ASP.NET Core MVC Šablona](Getting-Started-AspNetCore-MVC-Template.md)
Pokud chcete začít od nuly (s prázdným projektem) tak manuálně nainstalujte ABP Framework s pomocí následujících tutoriálů:
* [Konzolová Aplikace](Getting-Started-Console-Application.md)
* [ASP.NET Core Web Aplikace](Getting-Started-AspNetCore-Application.md)
## Zdrojový kód
ABP je hostovaný na GitHub. Zobrazit [zdrojový kód](https://github.com/abpframework/abp).
## Chcete přispět?
ABP je komunitně řízený open source projekt. Podívejte se na [průvodce pro přispěvatele](Contribution/Index.md) pokud chcete být součástí tohoto projektu.

292
docs/cs/docs-nav.json

@ -0,0 +1,292 @@
{
"items": [
{
"text": "Začínáme",
"items": [
{
"text": "Ze startovacích šablon",
"items": [
{
"text": "ASP.NET Core MVC",
"path": "Getting-Started-AspNetCore-MVC-Template.md"
}
]
},
{
"text": "Z prázdných projektů",
"items": [
{
"text": "S ASP.NET Core Web aplikací",
"path": "Getting-Started-AspNetCore-Application.md"
},
{
"text": "S konzolovou aplikací",
"path": "Getting-Started-Console-Application.md"
}
]
}
]
},
{
"text": "Tutoriály",
"items": [
{
"text": "Vývoj aplikace",
"items": [
{
"text": "S ASP.NET Core MVC",
"path": "Tutorials/AspNetCore-Mvc/Part-I.md"
}
]
}
]
},
{
"text": "CLI",
"path": "CLI.md"
},
{
"text": "Základy",
"items": [
{
"text": "Vkládání závislostí",
"path": "Dependency-Injection.md",
"items": [
{
"text": "AutoFac integrace",
"path": "Autofac-Integration.md"
}
]
},
{
"text": "Virtuální systém souborů",
"path": "Virtual-File-System.md"
},
{
"text": "Lokalizace",
"path": "Localization.md"
},
{
"text": "Zpracování výjimek",
"path": "Exception-Handling.md"
},
{
"text": "Validace"
},
{
"text": "Autorizace"
},
{
"text": "Ukládání do mezipaměti"
},
{
"text": "Audit"
},
{
"text": "Správa nastavení"
}
]
},
{
"text": "Události",
"items": [
{
"text": "Event bus (místní)"
},
{
"text": "Distribuovaný event bus",
"items": [
{
"text": "RabbitMQ integrace"
}
]
}
]
},
{
"text": "Služby",
"items": [
{
"text": "Serializace objektu"
},
{
"text": "Serializace JSON"
},
{
"text": "Emailování"
},
{
"text": "GUIDy"
},
{
"text": "Vláknování"
},
{
"text": "Časování"
}
]
},
{
"text": "Multitenance",
"path": "Multi-Tenancy.md"
},
{
"text": "Vývoj modulů",
"items": [
{
"text": "Základy",
"path": "Module-Development-Basics.md"
},
{
"text": "Zásuvné moduly"
},
{
"text": "Nejlepší praktiky",
"path": "Best-Practices/Index.md"
}
]
},
{
"text": "Domain driven design",
"path": "Domain-Driven-Design.md",
"items": [
{
"text": "Doménová vrstva",
"items": [
{
"text": "Entity & agregované kořeny",
"path": "Entities.md"
},
{
"text": "Hodnotové objekty"
},
{
"text": "Repozitáře",
"path": "Repositories.md"
},
{
"text": "Doménové služby"
},
{
"text": "Specifikace"
}
]
},
{
"text": "Aplikační vrstva",
"items": [
{
"text": "Aplikační služby",
"path": "Application-Services.md"
},
{
"text": "Objekty přenosu dat"
},
{
"text": "Jednotka práce"
}
]
}
]
},
{
"text": "ASP.NET Core",
"items": [
{
"text": "API",
"items": [
{
"text": "Automatické API řadiče",
"path": "AspNetCore/Auto-API-Controllers.md"
},
{
"text": "Dynamičtí C# API klienti",
"path": "AspNetCore/Dynamic-CSharp-API-Clients.md"
}
]
},
{
"text": "Uživatelské rozhraní",
"items": [
{
"text": "Správa klientských balíčků",
"path": "AspNetCore/Client-Side-Package-Management.md"
},
{
"text": "Svazování & minifikace",
"path": "AspNetCore/Bundling-Minification.md"
},
{
"text": "Tag pomocníci",
"path": "Tag-Helpers.md"
},
{
"text": "Motivy",
"path": "AspNetCore/Theming.md"
}
]
}
]
},
{
"text": "Přístup k datům",
"items": [
{
"text": "Entity Framework Core integrace",
"path": "Entity-Framework-Core.md"
},
{
"text": "MongoDB integrace",
"path": "MongoDB.md"
}
]
},
{
"text": "Pozadí",
"items": [
{
"text": "Úkony na pozadí",
"path": "Background-Jobs.md",
"items": [
{
"text": "Hangfire integrace",
"path": "Background-Jobs-Hangfire.md"
},
{
"text": "RabbitMQ integrace",
"path": "Background-Jobs-RabbitMq.md"
}
]
}
]
},
{
"text": "Vzorky",
"items": [
{
"text": "Mikroslužby demo",
"path": "Samples/Microservice-Demo.md"
}
]
},
{
"text": "Moduly aplikace",
"path": "Modules/Index.md"
},
{
"text": "Architektura mikroslužby",
"path": "Microservice-Architecture.md"
},
{
"text": "Testování"
},
{
"text": "Noční sestavení",
"path": "Nightly-Builds.md"
},
{
"text": "Průvodce pro přispěvatele",
"path": "Contribution/Index.md"
}
]
}

19
docs/docs-langs.json

@ -0,0 +1,19 @@
{
"Languages":[
{
"DisplayName" : "Čeština",
"Code" : "cs",
"IsDefault": false
},
{
"DisplayName" : "English",
"Code" : "en",
"IsDefault": true
},
{
"DisplayName" : "简体中文",
"Code" : "zh-Hans",
"IsDefault": false
}
]
}

6
docs/en/AspNetCore/Auto-API-Controllers.md

@ -2,7 +2,7 @@
Once you create an [application service](../Application-Services.md), you generally want to create an API controller to expose this service as an HTTP (REST) API endpoint. A typical API controller does nothing but redirects method calls to the application service and configures the REST API using attributes like [HttpGet], [HttpPost], [Route]... etc. Once you create an [application service](../Application-Services.md), you generally want to create an API controller to expose this service as an HTTP (REST) API endpoint. A typical API controller does nothing but redirects method calls to the application service and configures the REST API using attributes like [HttpGet], [HttpPost], [Route]... etc.
ABP can **automagically** configures your application services as MVC API Controllers by convention. Most of time you don't care about its detailed configuration, but it's possible fully customize it. ABP can **automagically** configure your application services as API Controllers by convention. Most of time you don't care about its detailed configuration, but it's possible to fully customize it.
## Configuration ## Configuration
@ -16,7 +16,9 @@ public class BookStoreWebModule : AbpModule
{ {
Configure<AbpAspNetCoreMvcOptions>(options => Configure<AbpAspNetCoreMvcOptions>(options =>
{ {
options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly); options
.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly);
}); });
} }
} }

3
docs/en/AspNetCore/Tag-Helpers.md

@ -1,3 +0,0 @@
# Tag Helpers
TODO

3
docs/en/AspNetCore/Tag-Helpers/Dynamic-Forms.md

@ -0,0 +1,3 @@
## Dynamic Forms
This is not documented yet. You can see a [demo](http://bootstrap-taghelpers.abp.io/Components/DynamicForms) for now.

0
docs/en/Tag-Helpers.md → docs/en/AspNetCore/Tag-Helpers/Index.md

3
docs/en/Aspect-Oriented-Programming.md

@ -0,0 +1,3 @@
## Dynamic Proxying / Interceptors
TODO

137
docs/en/CLI.md

@ -0,0 +1,137 @@
# ABP CLI
ABP CLI (Command Line Interface) is a command line tool to perform some common operations for ABP based solutions.
## Installation
ABP CLI is a [dotnet global tool](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools). Install it using a command line window:
````bash
dotnet tool install -g Volo.Abp.Cli
````
To update an existing installation:
````bash
dotnet tool update -g Volo.Abp.Cli
````
## Commands
### new
Generates a new solution based on the ABP [startup templates](Startup-Templates/Index.md).
Basic usage:
````bash
abp new <solution-name> [options]
````
Example:
````bash
abp new Acme.BookStore
````
* Acme.BookStore is the solution name here.
* Common convention is to name a solution is like *YourCompany.YourProject*. However, you can use different naming like *YourProject* (single level namespacing) or *YourCompany.YourProduct.YourModule* (three levels namespacing).
#### Options
* `--template` or `-t`: Specifies the template name. Default template name is `mvc`. Available templates:
* `mvc` (default): ASP.NET Core [MVC application template](Startup-Templates/Mvc.md). Additional options:
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
* `--tiered`: Creates a tiered solution where Web and Http API layers are physically separated. If not specified, it creates a layered solution which is less complex and suitable for most scenarios.
* `mvc-module`: ASP.NET Core [MVC module template](Startup-Templates/Mvc-Module.md). Additional options:
* `--no-ui`: Specifies to not include the UI. This makes possible to create service-only modules (a.k.a. microservices - without UI).
* `--output-folder` or `-o`: Specifies the output folder. Default value is the current directory.
### add-package
Adds a new ABP package to a project by,
* Adding related nuget package as a dependency to the project.
* Adding `[DependsOn(...)]` attribute to the module class in the project (see the [module development document](Module-Development-Basics.md)).
> Notice that the added module may require additional configuration which is generally indicated in the documentation of the related package.
Basic usage:
````bash
abp add-package <package-name> [options]
````
Example:
````
abp add-package Volo.Abp.MongoDB
````
* This example adds the Volo.Abp.MongoDB package to the project.
#### Options
* `--project` or `-p`: Specifies the project (.csproj) file path. If not specified, CLI tries to find a .csproj file in the current directory.
### add-module
Adds a multi-package module to a solution by finding all packages of the module, finding related projects in the solution and adding each package to the corresponding project in the solution.
> A business module generally consists of several packages (because of layering, different database providr options or other reasons). Using `add-module` command dramatically simplifies adding a module to a solution. However, each module may require some additional configurations which is generally indicated in the documentation of the related module.
Basic usage:
````bash
abp add-module <module-name> [options]
````
Example:
```bash
abp add-module Volo.Blogging
```
* This example add the Volo.Blogging module to the solution.
#### Options
* `--solution` or `-s`: Specifies the solution (.sln) file path. If not specified, CLI tries to find a .sln file in the current directory.
* `--skip-db-migrations`: For EF Core database provider, it automatically adds a new code first migration (`Add-Migration`) and updates the database (`Update-Database`) if necessary. Specify this option to skip this operation.
### update
Updating all ABP related packages can be tedious since there are many packages of the framework and modules. This command automatically updates all ABP related packages in a solution or project to the latest versions.
Usage:
````bash
abp update [options]
````
* If you run in a directory with a .sln file, it updates all ABP related packages of the all projects of the solution to the latest versions.
* If you run in a directory with a .csproj file, it updates all ABP related packages of the project to the latest versions.
#### Options
* `--include-previews` or `-p`: Includes preview, beta and rc packages while checking the latest versions.
### help
Writes basic usage information of the CLI.
Usage:
````bash
abp help [command-name]
````
Examples:
````bash
abp help # Shows a general help.
abp help new # Shows help about the "new" command.
````

3
docs/en/Caching.md

@ -0,0 +1,3 @@
# Caching
TODO

38
docs/en/Contribution/Localization-Text-Files.md

@ -2,19 +2,39 @@
Here, a list of localization text files for anyone wants to contribute to localization of the texts coming from the framework. We will keep this list up to date: Here, a list of localization text files for anyone wants to contribute to localization of the texts coming from the framework. We will keep this list up to date:
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json * https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json * https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json
* https://github.com/abpframework/abp/tree/master/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/en.json * https://github.com/abpframework/abp/tree/master/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Web/Localization/Resources/Blogging/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json * https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json * https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Web/Localization/Resources/Blogging/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json * https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Web/Localization/Resources/Docs/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Localization/Resources/FeatureManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Localization/ApplicationContracts/en.json * https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json
* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Localization/Resources/AbpPermissionManagement/en.json * https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Localization/Resources/AbpPermissionManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Localization/Resources/AbpTenantManagement/Web/en.json * https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Localization/Resources/AbpSettingManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/Localization/ApplicationContracts/en.json * https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc/src/MyCompanyName.MyProjectName.Domain/Localization/MyProjectName/en.json * https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Localization/Resources/AbpTenantManagement/Web/en.json
* https://github.com/abpframework/abp/tree/master/templates/module/src/MyCompanyName.MyProjectName.Domain/MyCompanyName/MyProjectName/Localization/Domain/en.json * https://github.com/abpframework/abp/tree/master/samples/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json
* https://github.com/abpframework/abp/tree/master/templates/module/src/MyCompanyName.MyProjectName.Web/Localization/Resources/MyProjectName/en.json * https://github.com/abpframework/abp/tree/master/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/en.json
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Application.Contracts/Localization/MyProjectName/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/DomainShared/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Web/Localization/MyProjectName/Web/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json

3
docs/en/CorrelationId.md

@ -0,0 +1,3 @@
# Correlation ID
TODO

3
docs/en/Data-Filtering.md

@ -0,0 +1,3 @@
# Data Filtering
TODO

3
docs/en/Data-Seeding.md

@ -0,0 +1,3 @@
# Data Seeding
TODO

3
docs/en/Distributed-Event-Bus.md

@ -0,0 +1,3 @@
# Distributed Event Bus
TODO

3
docs/en/Extension-Methods-And-Helpers.md

@ -0,0 +1,3 @@
# Extension Methods & Helpers
TODO

77
docs/en/Getting-Started-AspNetCore-MVC-Template.md

@ -1,40 +1,45 @@
## ASP.NET Core MVC Template ## Getting Started With the ASP.NET Core MVC Template
This tutorials explains how to create a new ASP.NET Core MVC web application using the startup template, configure and run it. This tutorials explains how to create a new ASP.NET Core MVC web application using the startup template, configure and run it.
### Creating a new project ### Creating a New Project
Go to [the template creation page](https://abp.io/Templates), enter a project name and create your project as shown below: This tutorial uses **ABP CLI** to create a new project. See the [Get Started](https://abp.io/get-started) page for other options.
![bookstore-create--template](images/bookstore-create-template.png) Install the ABP CLI using a command line window, if you've not installed before:
When you click the *create* button, a new Visual Studio solution is created and downloaded with the name you have provided. ````bash
dotnet tool install -g Volo.Abp.Cli
````
#### Pre Requirements Use `abp new` command in an empty folder to create your project:
The downloaded project requires; ````
abp new Acme.BookStore
````
* [Visual Studio 2017 (v15.7.0+)](https://visualstudio.microsoft.com/tr/downloads/) > You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.
* [.NET Core 2.1.1+](https://www.microsoft.com/net/download/dotnet-core/)
### The Solution Structure `new` command creates a **layered MVC application** with **Entity Framework Core** as the database provider. However, it has additional options. See the [CLI documentation](CLI.md) for all available options.
Extract the zip file downloaded and open in **Visual Studio 2017 (15.9.0+)**: #### Pre Requirements
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v2.png) The created solution requires;
The solution has a layered structure (based on Domain Driven Design) where; * [Visual Studio 2017 (v15.9.0+)](https://visualstudio.microsoft.com/tr/downloads/)
* [.NET Core 2.2+](https://www.microsoft.com/net/download/dotnet-core/)
* ``.Domain`` is the domain layer. ### The Solution Structure
* ``.Application`` is the application layer.
* ``.Web`` is the presentation layer. Open the solution in **Visual Studio**:
* ``.EntityFrameworkCore`` is the EF Core integration package.
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v3.png)
EF Core database migrations are separated to a project named `.EntityFrameworkCore.DbMigrations`. The solution has a layered structure (based on [Domain Driven Design](Domain-Driven-Design.md)) and contains unit & integration test projects properly configured to work with **EF Core** & **SQLite in-memory** database.
The solution also contains unit & integration test projects properly configured to work with **EF Core** & **SQLite in-memory** database. > See [MVC application template document](Startup-Templates/Mvc.md) to understand the solution structure in details.
### Creating the Database ### Database Connection String
Check the **connection string** in the `appsettings.json` file under the `.Web` project: Check the **connection string** in the `appsettings.json` file under the `.Web` project:
@ -46,9 +51,29 @@ Check the **connection string** in the `appsettings.json` file under the `.Web`
} }
```` ````
The solution is configured to use **Entity Framework Core** with **MS SQL Server**. EF Core supports [various](https://docs.microsoft.com/en-us/ef/core/providers/) database providers, so you can use another DBMS if you want. The solution is configured to use **Entity Framework Core** with **MS SQL Server**. EF Core supports [various](https://docs.microsoft.com/en-us/ef/core/providers/) database providers, so you can use another DBMS if you want. Change the connection string if you need.
### Create Database & Apply Database Migrations
You have two options to create the database.
Right click to the `.Web` project and select **Set as StartUp Project**: #### Using the DbMigrator Application
The solution contains a console application (named `Acme.BookStore.DbMigrator` in this sample) that can create database, apply migrations and seed initial data. It is useful on development as well as on production environment.
> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one.
Right click to the `.DbMigrator` project and select **Set as StartUp Project**:
![set-as-startup-project](images/set-as-startup-project.png)
Hit F5 (or Ctrl+F5) to run the application. It will have an output like shown below:
![set-as-startup-project](images/db-migrator-app.png)
#### Using EF Core Update-Database Command
Ef Core has `Update-Database` command which creates database if necessary and applies pending migrations. Right click to the `.Web` project and select **Set as StartUp Project**:
![set-as-startup-project](images/set-as-startup-project.png) ![set-as-startup-project](images/set-as-startup-project.png)
@ -58,17 +83,19 @@ Open the **Package Manager Console**, select `.EntityFrameworkCore.DbMigrations`
This will create a new database based on the configured connection string. 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.
### Running the Application ### Running the Application
You can now run the application which will open the **home** page: Ensure that the `.Web` project is the startup project. Run the application which will open the **home** page in your browser:
![bookstore-homepage](images/bookstore-homepage.png) ![bookstore-homepage](images/bookstore-homepage.png)
Click the **Login** button, enter `admin` as the username and `1q2w3E*` as the password to login to the application. Click the **Login** button, enter `admin` as the username and `1q2w3E*` as the password to login to the application.
The startup template includes the **identity management** module. Once you login, the Identity management menu will be available where you can manage **roles**, **users** and their **permissions**. The startup template includes the **identity management** and **tenant management** modules. Once you login, the Administration menu will be available where you can manage **tenants**, **roles**, **users** and their **permissions**. User management page is shown below:
![bookstore-user-management](images/bookstore-user-management.png) ![bookstore-user-management](images/bookstore-user-management-v2.png)
### What's Next? ### What's Next?

2
docs/en/Index.md

@ -6,7 +6,7 @@ Explore the left navigation menu to deep dive in the documentation.
## Project Status ## Project Status
ABP is the **next generation** of the open source [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework. It's currently in early preview stage and not ready to use in production. The documentation is still in progress and it is incomplete yet. ABP is the **next generation** of the open source [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework. It's currently in early preview stage and not ready to use in production. The documentation is still in progress and it is far from complete.
For short-term and production level applications, it's suggested to use [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework which has rich feature set, mature, actively maintained and up-to-date. For short-term and production level applications, it's suggested to use [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework which has rich feature set, mature, actively maintained and up-to-date.

3
docs/en/Integration-Tests.md

@ -0,0 +1,3 @@
# Integration Tests
TODO!

3
docs/en/JavaScript/Dynamic-JavaScript-API-Clients.md

@ -0,0 +1,3 @@
## Dynamic JavaScript API Clients
TODO

3
docs/en/Local-Event-Bus.md

@ -0,0 +1,3 @@
# Local Event Bus
TODO

3
docs/en/SMS-Sending.md

@ -0,0 +1,3 @@
# Emailing
TODO!

3
docs/en/Settings.md

@ -0,0 +1,3 @@
# Settings
TODO!

3
docs/en/Specifications.md

@ -0,0 +1,3 @@
# Specifications
TODO!

11
docs/en/Startup-Templates/Index.md

@ -0,0 +1,11 @@
# Startup Templates
While you can start with an empty project and add needed packages manually, startup templates makes easy and comfortable to start a new solution with the ABP framework.
Click to the name from the list below to see the documentation of the related startup template:
* [**mvc**](Mvc.md): ASP.NET Core MVC application template.
* [**mvc-module**](Mvc-Module.md): ASP.NET Core MVC module/service template.

160
docs/en/Startup-Templates/Mvc-Module.md

@ -0,0 +1,160 @@
# MVC Module Startup Template
This template can be used to create a **reusable [application module](../Modules/Index.md)** based on the [module development best practices & conventions](../Best-Practices/Index.md). It is also suitable for creating **microservices** (with or without UI).
## How to Start With?
You can use the [ABP CLI](../CLI.md) to create a new project using this startup template. Alternatively, you can directly create & download from the [Get Started](https://abp.io/get-started) page. CLI approach is used here.
First, install the ABP CLI if you haven't installed before:
```bash
dotnet tool install -g Volo.Abp.Cli
```
Then use the `abp new` command in an empty folder to create a new solution:
```bash
abp new Acme.IssueManagement -t mvc-module
```
- `Acme.IssueManagement` is the solution name, like *YourCompany.YourProduct*. You can use single level, two-levels or three-levels naming.
### Without User Interface
The template comes with a 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
````
## Solution Structure
Based on the options you've specified, you will get a slightly different solution structure. If you don't specify any option, you will have a solution like shown below:
![issuemanagement-module-solution](../images/issuemanagement-module-solution.png)
Projects are organized as `src`, `test` and `host` folders:
* `src` folder contains the actual module which is layered based on [DDD](../Domain-Driven-Design.md) principles.
* `test` folder contains unit & integration tests.
* `host` folder contains applications with different configurations to demonstrate how to host the module in an application. These are not a part of the module, but useful on development.
The diagram below shows the layers & project dependencies of the module:
![layered-project-dependencies-module](../images/layered-project-dependencies-module.png)
Each section below will explain the related project & its dependencies.
### .Domain.Shared Project
This project contains constants, enums and other objects these are actually a part of the domain layer, but needed to be used by all layers/projects in the solution.
An `IssueType` enum and an `IssueConts` class (which may have some constant fields for the `Issue` entity, like `MaxTitleLength`) are good candidates for this project.
- This project has no dependency to other projects in the solution. All other projects depend on this directly or indirectly.
### .Domain Project
This is the domain layer of the solution. It mainly contains [entities, aggregate roots](../Entities.md), [domain services](../Domain-Services.md), [value types](../Value-Types.md), [repository interfaces](../Repositories.md) and other domain objects.
An `Issue` entity, an `IssueManager` domain service and an `IIssueRepository` interface are good candidates for this project.
- Depends on the `.Domain.Shared` because it uses constants, enums and other objects defined in that project.
### .Application.Contracts Project
This project mainly contains [application service](../Application-Services.md) **interfaces** and [Data Transfer Objects](../Data-Transfer-Objects.md) (DTO) of the application layer. It does exists to separate interface & implementation of the application layer. In this way, the interface project can be shared to the clients as a contract package.
An `IIssueAppService` interface and an `IssueCreationDto` class are good candidates for this project.
- Depends on the `.Domain.Shared` because it may use constants, enums and other shared objects of this project in the application service interfaces and DTOs.
### .Application Project
This project contains the [application service](../Application-Services.md) **implementations** of the interfaces defined in the `.Application.Contracts` project.
An `IssueAppService` class is a good candidate for this project.
- Depends on the `.Application.Contracts` project to be able to implement the interfaces and use the DTOs.
- Depends on the `.Domain` project to be able to use domain objects (entities, repository interfaces... etc.) to perform the application logic.
### .EntityFrameworkCore Project
This is the integration project for EF Core. It defines the `DbContext` and implements repository interfaces defined in the `.Domain` project.
- Depends on the `.Domain` project to be able to reference to entities and repository interfaces.
> You can delete this project if you don't want to support EF Core for your module.
### .MongoDB Project
This is the integration project for MongoDB.
- Depends on the `.Domain` project to be able to reference to entities and repository interfaces.
> You can delete this project if you don't want to support MongoDB for your module.
### Test Projects
The solution has multiple test projects, one for each layer:
- `.Domain.Tests` is used to test the domain layer.
- `.Application.Tests` is used to test the application layer.
- `.EntityFrameworkCore.Tests` is used to test EF Core configuration and custom repositories.
- `.MongoDB.Tests` is used to test EF Core configuration and custom repositories.
- `.TestBase` is a base (shared) project for all tests.
In addition, `.HttpApi.Client.ConsoleTestApp` is a console application (not an automated test project) which demonstrate the usage of HTTP APIs from a Dotnet application.
Test projects are prepared for integration testing;
- It is fully integrated to ABP framework and all services in your application.
- It uses SQLite in-memory database for EF Core. For MongoDB, it uses the [Mongo2Go](https://github.com/Mongo2Go/Mongo2Go) library.
- Authorization is disabled, so any application service can be easily used in tests.
You can still create unit tests for your classes which will be harder to write (because you will need to prepare mock/fake objects), but faster to run (because it only tests a single class and skips all initialization process).
> Domain & Application tests are using EF Core. If you remove EF Core integration or you want to use MongoDB for testing these layers, you should manually change project references & module dependencies.
### Host Projects
The solution has a few host applications to run your module on development. Host applications are used to run your module in a fully configured application. It is useful on development. Host applications includes some other modules in addition to the module being developed:
*
Host applications support two types of scenarios.
#### Single (Unified) Application Scenario
If your module has a UI, then `.Web.Unified` application is used to host the UI and API on a single point. It has its own `appsettings.json` file (that includes the database connection string) and EF Core database migrations.
For the `.Web.Unified` application, there is a single database, named `YourProjectName_Unified` (like *IssueManagement_Unified* for this sample).
> If you've selected the `--no-ui` option, this project will not be in your solution.
##### How to Run?
Set it as the startup project, run `Update-Database` command for the EF Core from Package Manager Console and run your application. Default username is `admin` and password is `1q2w3E*`.
#### Separated Deployment & Databases Scenario
In this scenario, there are three applications;
* `.IdentityServer` application is an authentication server used by other applications. It has its own `appsettings.json` that contains database connection and other configurations.
* `.HttpApi.Host` hosts the HTTP API of the module. It has its own `appsettings.json` that contains database connections and other configurations.
* `.Web.Host` host the UI of the module. This project contains an `appsettings.json` file, but it does not have a connection string because it never connects to the database. Instead, it mainly contains endpoint of the remote API server and the authentication server.
The diagram below shows the relation of the applications:
![tiered-solution-applications](../images/tiered-solution-applications.png)
`.Web.Host` project uses OpenId Connect Authentication to get identity and access tokens for the current user from the `.IdentityServer`. Then uses the access token to call the `.HttpApi.Host`. HTTP API server uses bearer token authentication to obtain claims from the access token to authorize the current user.
##### How to Run?
You should run the application with the given order:
- First, run the `.IdentityServer` since other applications depends on it.
- Then run the `.HttpApi.Host` since it is used by the `.Web.Host` application.
- Finally, you can run the `.Web.Host` project and login to the application using `admin` as the username and `1q2w3E*` as the password.

260
docs/en/Startup-Templates/Mvc.md

@ -0,0 +1,260 @@
# MVC Application Startup Template
## Introduction
This template provides a layered (or tiered, based on the preference) application structure based on the [Domain Driven Design](../Domain-Driven-Design.md) (DDD) practices.
This document explains the solution structure and projects in details.
* See [Getting Started With the ASP.NET Core MVC Template](../Getting-Started-AspNetCore-MVC-Template.md) to create a new solution and run it for this template.
* See the [ASP.NET Core MVC Tutorial](../Tutorials/AspNetCore-Mvc/Part-I.md) to learn how to develop applications using this template.
## How to Start With?
You can use the [ABP CLI](../CLI.md) to create a new project using this startup template. Alternatively, you can directly create & download from the [Get Started](https://abp.io/get-started) page. CLI approach is used here.
First, install the ABP CLI if you haven't installed before:
````bash
dotnet tool install -g Volo.Abp.Cli
````
Then use the `abp new` command in an empty folder to create a new solution:
````bash
abp new Acme.BookStore -t mvc
````
* `Acme.BookStore` is the solution name, like *YourCompany.YourProduct*. You can use single level, two-levels or three-levels naming.
* This example specified the template name (`-t` or `--template` option). However, `mvc` is already the default template if you don't specify it.
### Specify the Database Provider
This template supports the following database providers:
- `ef`: Entity Framework Core (default)
- `mongodb`: MongoDB
Use `-d` (or `--database-provider`) option to specify the database provider:
````bash
abp new Acme.BookStore -d mongodb
````
### Create a Tiered Solution
`--tiered` option is used to create a tiered solution where Web and Http API layers are physically separated. If not specified, it creates a layered solution which is less complex and suitable for most scenarios.
````bash
abp new Acme.BookStore --tiered
````
See the "Tiered Structure" section below for the tiered approach.
## Solution Structure
Based on the options you've specified, you will get a slightly different solution structure.
### Default Structure
If you don't specify any option, you will have a solution like shown below:
![bookstore-visual-studio-solution-v3](../images/bookstore-visual-studio-solution-v3.png)
Projects are organized in `src` and `test` folders. `src` folder contains the actual application which is layered based on [DDD](../Domain-Driven-Design.md) principles as mentioned before.
The diagram below shows the layers & project dependencies of the application:
![layered-project-dependencies](../images/layered-project-dependencies.png)
Each section below will explain the related project & its dependencies.
#### .Domain.Shared Project
This project contains constants, enums and other objects these are actually a part of the domain layer, but needed to be used by all layers/projects in the solution.
A `BookType` enum and a `BookConts` class (which may have some constant fields for the `Book` entity, like `MaxNameLength`) are good candidates for this project.
* This project has no dependency to other projects in the solution. All other projects depend on this directly or indirectly.
#### .Domain Project
This is the domain layer of the solution. It mainly contains [entities, aggregate roots](../Entities.md), [domain services](../Domain-Services.md), [value types](../Value-Types.md), [repository interfaces](../Repositories.md) and other domain objects.
A `Book` entity, a `BookManager` domain service and an `IBookRepository` interface are good candidates for this project.
* Depends on the `.Domain.Shared` because it uses constants, enums and other objects defined in that project.
#### .Application.Contracts Project
This project mainly contains [application service](../Application-Services.md) **interfaces** and [Data Transfer Objects](../Data-Transfer-Objects.md) (DTO) of the application layer. It does exists to separate interface & implementation of the application layer. In this way, the interface project can be shared to the clients as a contract package.
An `IBookAppService` interface and a `BookCreationDto` class are good candidates for this project.
* Depends on the `.Domain.Shared` because it may use constants, enums and other shared objects of this project in the application service interfaces and DTOs.
#### .Application Project
This project contains the [application service](../Application-Services.md) **implementations** of the interfaces defined in the `.Application.Contracts` project.
A `BookAppService` class is a good candidate for this project.
* Depends on the `.Application.Contracts` project to be able to implement the interfaces and use the DTOs.
* Depends on the `.Domain` project to be able to use domain objects (entities, repository interfaces... etc.) to perform the application logic.
#### .EntityFrameworkCore Project
This is the integration project for the EF Core. It defines the `DbContext` and implements repository interfaces defined in the `.Domain` project.
* Depends on the `.Domain` project to be able to reference to entities and repository interfaces.
> This project is available only if you are using EF Core as the database provider. If you select another database provider, its name will be different.
#### .EntityFrameworkCore.DbMigrations Project
Contains EF Core database migrations for the solution. It has a separated `DbContext` to dedicated to manage migrations.
ABP is a modular framework and with an ideal design, each module has its own `DbContext` class. This is where the migration `DbContext` comes into play and unifies all `DbContext` configurations into a single model to maintain a single database schema. For more advanced scenarios, you can have multiple databases (each contains a single or a few module tables) and multiple migration `DbContext`s (each maintains a different database schema).
Notice that the migration `DbContext` is only used for database migrations and *not used on runtime*.
* Depends on the `.EntityFrameworkCore` project since it re-uses the configuration defined for the `DbContext` of the application.
> This project is available only if you are using EF Core as the database provider.
#### .DbMigrator Project
This is a console application which simplifies to execute database migrations on development and production environments. When you run this application, it;
* Creates the database if necessary.
* Applies the pending database migrations.
* Seeds initial data if needed.
> This project has its own `appsettings.json` file. So, if you want to change the database connection string, remember to change this file too.
Especially, seeding initial data is important at this point. ABP has a modular data seed infrastructure. See [its documentation](../Data-Seeding.md) for more about the data seeding.
While creating database & applying migrations seems only necessary for relational databases, this projects comes even if you choose a NoSQL database provider (like MongoDB). In that case, it still seeds initial data which is necessary for the application.
* Depends on the `.EntityFrameworkCore.DbMigrations` project (for EF Core) since it needs to access to the migrations.
* Depends on the `.Application.Contracts` project to be able to access permission definitions, because initial data seeder grants all permissions for the admin role by default.
#### .HttpApi Project
This project is used to define your API Controllers.
Most of time you don't need to manually define API Controllers since ABP's [Auto API Controllers](../AspNetCore/Auto-API-Controllers.md) feature creates them automagically based on your application layer. However, in case of you need to write API controllers, this is the best place to do it.
* Depends on the `.Application.Contracts` project to be able to inject the application service interfaces.
#### .HttpApi.Client Project
This is a project that defines C# client proxies to use the HTTP APIs of the solution. You can share this library to 3rd-party clients, so they can easily consume your HTTP APIs in their Dotnet applications (For other type of applications, they can still use your APIs, either manually or using a tool in their own platform)
Most of time you don't need to manually create C# client proxies, thanks to ABP's [Dynamic C# API Clients](../AspNetCore/Dynamic-CSharp-API-Clients.md) feature.
`.HttpApi.Client.ConsoleTestApp` project is a console application created to demonstrate the usage of the client proxies.
* Depends on the `.Application.Contracts` project to be able to share the same application service interfaces and DTOs with the remote service.
> You can delete this project & dependencies if you don't need to create C# client proxies for your APIs.
#### .Web Project
This project contains the User Interface (UI) of the application. It contains razor pages, JavaScript files, style files, images and so on...
This project contains the main `appsettings.json` file that contains the connection string and other configuration of the application.
* Depends on the `.HttpApi` since UI layer needs to use APIs and application service interfaces of the solution.
> If you check the source code of the `.Web.csproj` file, you will see the references to the `.Application` and the `.EntityFrameworkCore.DbMigrations` projects.
>
> These references are actually not needed while coding your UI layer, because UI layer normally doesn't depend on the EF Core or the Application layer's implementation. This startup templates are ready for the tiered deployment, where API layer is hosted in a separate server than the UI layer.
>
> However, if you don't choose the `--tiered` option, these references will be in the .Web project to be able to host the Web, API and application layers in a single application endpoint.
>
> This gives you to ability to use domain entities & repositories in your presentation layer. However, this is considered as a bad practice according to the DDD.
#### Test Projects
The solution has multiple test projects, one for each layer:
* `.Domain.Tests` is used to test the domain layer.
* `.Application.Tests` is used to test the application layer.
* `.EntityFrameworkCore.Tests` is used to test EF Core configuration and custom repositories.
* `.Web.Tests` is used to test the UI.
* `.TestBase` is a base (shared) project for all tests.
In addition, `.HttpApi.Client.ConsoleTestApp` is a console application (not an automated test project) which demonstrate the usage of HTTP APIs from a Dotnet application.
Test projects are prepared for integration testing;
* It is fully integrated to ABP framework and all services in your application.
* It uses SQLite in-memory database for EF Core. For MongoDB, it uses the [Mongo2Go](https://github.com/Mongo2Go/Mongo2Go) library.
* Authorization is disabled, so any application service can be easily used in tests.
You can still create unit tests for your classes which will be harder to write (because you will need to prepare mock/fake objects), but faster to run (because it only tests a single class and skips all initialization process).
#### How to Run?
Set `.Web` as the startup project and run the application. Default username is `admin` and password is `1q2w3E*`.
See [Getting Started With the ASP.NET Core MVC Template](../Getting-Started-AspNetCore-MVC-Template.md) for more information.
### Tiered Structure
If you specify the `--tiered` option as described above, the solution created will be a tiered solution. The purpose of the tiered structure is to be able to **deploy Web application and HTTP API to different servers**:
![bookstore-visual-studio-solution-v3](../images/tiered-solution-servers.png)
* Browser runs your UI by executing HTML, CSS & JavaScript.
* Web servers hosts static UI files (CSS, JavaScript, image... etc.) & dynamic components (e.g. Razor pages). It performs HTTP requests to the API server to execute the business logic of the application.
* API Server hosts the HTTP APIs which then use application & domain layers of the application to perform the business logic.
* Finally, database server hosts your database.
So, the resulting solution allows a 4-tiered deployment, by comparing to 3-tiered deployment of the default structure explained before.
> Unless you actually need to such a 4-tiered deployment, its suggested to go with the default structure which is simpler to develop, deploy and maintain.
The solution structure is shown below:
![bookstore-visual-studio-solution-v3](../images/bookstore-visual-studio-solution-tiered.png)
As different from the default structure, two new projects come into play: `.IdentityServer` & `.HttpApi.Host`.
#### .IdentityServer Project
This project is used as an authentication server for other projects. `.Web` project uses OpenId Connect Authentication to get identity and access tokens for the current user from the IdentityServer. Then uses the access token to call the HTTP API server. HTTP API server uses bearer token authentication to obtain claims from the access token to authorize the current user.
![tiered-solution-applications](../images/tiered-solution-applications.png)
ABP uses the open source [IdentityServer4](https://identityserver.io/) framework for the authentication between applications. See [IdentityServer4 documentation](http://docs.identityserver.io) for details about the IdentityServer4 and OpenID Connect protocol.
It has its own `appsettings.json` that contains database connection and other configurations.
#### .HttpApi.Host Project
This project is an application that hosts the API of the solution. It has its own `appsettings.json` that contains database connection and other configurations.
#### .Web Project
Just like the default structure, this project contains the User Interface (UI) of the application. It contains razor pages, JavaScript files, style files, images and so on...
This project contains an `appsettings.json` file, but this time it does not have a connection string because it never connects to the database. Instead, it mainly contains endpoint of the remote API server and the authentication server.
#### Pre-requirements
* [Redis](https://redis.io/): The applications use Redis as as distributed cache. So, you need to have Redis installed & running.
#### How to Run?
You should run the application with the given order:
* First, run the `.IdentityServer` since other applications depends on it.
* Then run the `.HttpApi.Host` since it is used by the `.Web` application.
* Finally, you can run the `.Web` project and login to the application (using `admin` as the username and `1q2w3E*` as the password).
## What's Next?
- See [Getting Started With the ASP.NET Core MVC Template](../Getting-Started-AspNetCore-MVC-Template.md) to create a new solution and run it for this template.
- See the [ASP.NET Core MVC Tutorial](../Tutorials/AspNetCore-Mvc/Part-I.md) to learn how to develop applications using this template.

3
docs/en/Testing.md

@ -0,0 +1,3 @@
# Testing
TODO!

147
docs/en/Tutorials/AspNetCore-Mvc/Part-I.md

@ -2,43 +2,45 @@
### About this Tutorial ### About this Tutorial
In this tutorial series, you will build an application that is used to manage a list of books & their authors. **Entity Framework Core** (EF Core) will be used as the ORM provider (as it comes pre-configured with the [startup template](https://abp.io/Templates)). In this tutorial series, you will build an application that is used to manage a list of books & their authors. **Entity Framework Core** (EF Core) will be used as the ORM provider as it is the default database provider.
This is the first part of the tutorial series. See all parts: This is the first part of the ASP.NET Core MVC tutorial series. See all parts:
- **Part I: Create the project and a book list page (this tutorial)** - **Part I: Create the project and a book list page (this tutorial)**
- [Part II: Create, Update and Delete books](Part-II.md) - [Part II: Create, Update and Delete books](Part-II.md)
- [Part III: Integration Tests](Part-III.md) - [Part III: Integration Tests](Part-III.md)
You can download the **source code** of the application [from here](https://github.com/volosoft/abp/tree/master/samples/BookStore). You can access to the **source code** of the application from [the GitHub repository](https://github.com/volosoft/abp/tree/master/samples/BookStore).
### Creating the Project ### Creating the Project
Go to the [startup template page](https://abp.io/Templates) and download a new project named `Acme.BookStore`, create the database and run the application by following the [template document](../../Getting-Started-AspNetCore-MVC-Template.md). Create a new project named `Acme.BookStore`, create the database and run the application by following the [Getting Started document](../../Getting-Started-AspNetCore-MVC-Template.md).
### Solution Structure ### Solution Structure
This is the how the layered solution structure looks after it's created from the startup template: This is how the layered solution structure looks after it's created:
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v2.png) ![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v3.png)
> You can see [MVC application template document](../../Startup-Templates/Mvc.md) to understand the solution structure in details. However, you will understand the basics with this tutorial.
### Create the Book Entity ### Create the Book Entity
Define [entities](../../Entities.md) in the **domain layer** (`Acme.BookStore.Domain` project) of the solution. The main entity of the application is the `Book`: Domain layer in the startup template is separated into two projects:
- `Acme.BookStore.Domain` contains your [entities](../../Entities.md), [domain services](../../Domain-Services.md) and other core domain objects.
- `Acme.BookStore.Domain.Shared` contains constants, enums or other domain related objects those can be shared with clients.
Define [entities](../../Entities.md) in the **domain layer** (`Acme.BookStore.Domain` project) of the solution. The main entity of the application is the `Book`. Create a class, named `Book`, in the `Acme.BookStore.Domain` project as shown below:
````C# ````C#
using System; using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore namespace Acme.BookStore
{ {
[Table("Books")]
public class Book : AuditedAggregateRoot<Guid> public class Book : AuditedAggregateRoot<Guid>
{ {
[Required]
[StringLength(128)]
public string Name { get; set; } public string Name { get; set; }
public BookType Type { get; set; } public BookType Type { get; set; }
@ -50,22 +52,22 @@ namespace Acme.BookStore
} }
```` ````
* ABP has two fundamental base classes for entities: `AggregateRoot` and `Entity`. **Aggregate Root** is one of the **Domain Driven Design (DDD)** concepts. See [entity document](../../Entities.md) for more details and best practices. * ABP has two fundamental base classes for entities: `AggregateRoot` and `Entity`. **Aggregate Root** is one of the **Domain Driven Design (DDD)** concepts. See [entity document](../../Entities.md) for details and best practices.
* `Book` entity inherits `AuditedAggregateRoot` which adds some auditing properties (`CreationTime`, `CreatorId`, `LastModificationTime`... etc.) on top of the `AggregateRoot` class. * `Book` entity inherits `AuditedAggregateRoot` which adds some auditing properties (`CreationTime`, `CreatorId`, `LastModificationTime`... etc.) on top of the `AggregateRoot` class.
* `Guid` is the **primary key type** of the `Book` entity. * `Guid` is the **primary key type** of the `Book` entity.
* Used **data annotation attributes** in this code for EF Core mappings. Alternatively you could use EF Core's [fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling) instead. * Used **data annotation attributes** in this code for EF Core mappings. Alternatively you could use EF Core's [fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling) instead.
#### BookType Enum #### BookType Enum
The `BookType` enum used above is defined as below: Define the `BookType` enum in the `Acme.BookStore.Domain.Shared` project:
````C# ````C#
namespace Acme.BookStore namespace Acme.BookStore
{ {
public enum BookType : byte public enum BookType
{ {
Undefined, Undefined,
Advanture, Adventure,
Biography, Biography,
Dystopia, Dystopia,
Fantastic, Fantastic,
@ -91,14 +93,15 @@ EF Core requires you to relate entities with your DbContext. The easiest way to
#### Configure Your Book Entity #### Configure Your Book Entity
Open BookStoreDbContextModelCreatingExtensions.cs file from the `Acme.BookStore.EntityFrameworkCore` project, add following code to the end of ConfigureBookStore method to configure Book entity: Open `BookStoreDbContextModelCreatingExtensions.cs` file in the `Acme.BookStore.EntityFrameworkCore` project and add following code to the end of the `ConfigureBookStore` method to configure the Book entity:
````C# ````C#
builder.Entity<Book>(b => builder.Entity<Book>(b =>
{ {
b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema); b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema);
b.ConfigureExtraProperties(); b.ConfigureAuditedAggregateRoot(); //auto configure for the base class props
}); b.Property(x => x.Name).IsRequired().HasMaxLength(128);
});
```` ````
#### Add New Migration & Update the Database #### Add New Migration & Update the Database
@ -115,26 +118,27 @@ PM> Update-Database
#### Add Sample Data #### Add Sample Data
`Update-Database` command created the `Books` table in the database. Open your database and enter a few sample rows, so you can show them on the page: `Update-Database` command created the `AppBooks` table in the database. Open your database and enter a few sample rows, so you can show them on the page:
![bookstore-books-table](images/bookstore-books-table.png) ![bookstore-books-table](images/bookstore-books-table.png)
### Create the Application Service ### Create the Application Service
The next step is to create an [application service](../../Application-Services.md) to manage (create, list, update, delete...) the books. The next step is to create an [application service](../../Application-Services.md) to manage (create, list, update, delete...) the books. Application layer in the startup template is separated into two projects:
* `Acme.BookStore.Application.Contracts` mainly contains your DTOs and application service interfaces.
* `Acme.BookStore.Application` contains the implementations of your application services.
#### BookDto #### BookDto
Create a DTO class named `BookDto` into the `Acme.BookStore.Application` project: Create a DTO class named `BookDto` into the `Acme.BookStore.Application.Contracts` project:
````C# ````C#
using System; using System;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.AutoMapper;
namespace Acme.BookStore namespace Acme.BookStore
{ {
[AutoMapFrom(typeof(Book))]
public class BookDto : AuditedEntityDto<Guid> public class BookDto : AuditedEntityDto<Guid>
{ {
public string Name { get; set; } public string Name { get; set; }
@ -151,20 +155,34 @@ namespace Acme.BookStore
* **DTO** classes are used to **transfer data** between the *presentation layer* and the *application layer*. See the [Data Transfer Objects document](../../Data-Transfer-Objects.md) for more details. * **DTO** classes are used to **transfer data** between the *presentation layer* and the *application layer*. See the [Data Transfer Objects document](../../Data-Transfer-Objects.md) for more details.
* `BookDto` is used to transfer book data to the presentation layer in order to show the book information on the UI. * `BookDto` is used to transfer book data to the presentation layer in order to show the book information on the UI.
* `BookDto` is derived from the `AuditedEntityDto<Guid>` which has audit properties just like the `Book` class defined above. * `BookDto` is derived from the `AuditedEntityDto<Guid>` which has audit properties just like the `Book` class defined above.
* `[AutoMapFrom(typeof(Book))]` is used to create AutoMapper mapping from the `Book` class to the `BookDto` class. In this way, you get automatic conversion of `Book` objects to `BookDto` objects (instead of manually copy all properties).
It will be needed to convert `Book` entities to `BookDto` objects while returning books to the presentation layer. [AutoMapper](https://automapper.org) library can automate this conversion when you define the proper mapping. Startup template comes with AutoMapper configured, so you can just define the mapping in the `BookStoreApplicationAutoMapperProfile` class in the `Acme.BookStore.Application` project:
````csharp
using AutoMapper;
namespace Acme.BookStore
{
public class BookStoreApplicationAutoMapperProfile : Profile
{
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
}
}
}
````
#### CreateUpdateBookDto #### CreateUpdateBookDto
Create a DTO class named `CreateUpdateBookDto` into the `Acme.BookStore.Application` project: Create a DTO class named `CreateUpdateBookDto` into the `Acme.BookStore.Application.Contracts` project:
````c# ````c#
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Volo.Abp.AutoMapper;
namespace Acme.BookStore namespace Acme.BookStore
{ {
[AutoMapTo(typeof(Book))]
public class CreateUpdateBookDto public class CreateUpdateBookDto
{ {
[Required] [Required]
@ -184,11 +202,17 @@ namespace Acme.BookStore
```` ````
* This DTO class is used to get book information from the user interface while creating or updating a book. * This DTO class is used to get book information from the user interface while creating or updating a book.
* It defines data annotation attributes (like `[Required]`) to define validations for the properties. DTOs are automatically validated by ABP. * It defines data annotation attributes (like `[Required]`) to define validations for the properties. DTOs are [automatically validated](../../Validation.md) by the ABP framework.
Like done for the `BookDto` above, create a mapping from the `CreateUpdateBookDto` object to the `Book` entity:
````csharp
CreateMap<CreateUpdateBookDto, Book>();
````
#### IBookAppService #### IBookAppService
Define an interface named `IBookAppService` for the book application service: Define an interface named `IBookAppService` in the `Acme.BookStore.Application.Contracts` project:
````C# ````C#
using System; using System;
@ -210,13 +234,13 @@ namespace Acme.BookStore
} }
```` ````
* Defining interfaces for application services is <u>not required</u> by the framework. However, it's suggested as best practice. * Defining interfaces for application services is <u>not required</u> by the framework. However, it's suggested as a best practice.
* `IAsyncCrudAppService` defines common **CRUD** methods: `GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync` and `DeleteAsync`. It's not required to extend it. Instead, you could inherit from the empty `IApplicationService` interface and define your own methods. * `IAsyncCrudAppService` defines common **CRUD** methods: `GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync` and `DeleteAsync`. It's not required to extend it. Instead, you could inherit from the empty `IApplicationService` interface and define your own methods manually.
* There are some variations of the `IAsyncCrudAppService` where you can use a single DTO or separated DTOs for each method. * There are some variations of the `IAsyncCrudAppService` where you can use separated DTOs for each method.
#### BookAppService #### BookAppService
Implement the `IBookAppService` as named `BookAppService`: Implement the `IBookAppService` as named `BookAppService` in the `Acme.BookStore.Application` project:
````C# ````C#
using System; using System;
@ -241,23 +265,23 @@ namespace Acme.BookStore
```` ````
* `BookAppService` is derived from `AsyncCrudAppService<...>` which implements all the CRUD methods defined above. * `BookAppService` is derived from `AsyncCrudAppService<...>` which implements all the CRUD methods defined above.
* `BookAppService` injects `IRepository<Book, Guid>` which is the default repository created for the `Book` entity. ABP automatically creates repositories for each aggregate root (or entity). See the [repository document](../../Repositories.md). * `BookAppService` injects `IRepository<Book, Guid>` which is the default repository for the `Book` entity. ABP automatically creates default repositories for each aggregate root (or entity). See the [repository document](../../Repositories.md).
* `BookAppService` uses `IObjectMapper` to convert `Book` objects to `BookDto` objects and `CreateUpdateBookDto` objects to `Book` objects. The Startup template uses the [AutoMapper](http://automapper.org/) library as object mapping provider. You defined mappings using the `AutoMapFrom` and the `AutoMapTo` attributes above. See the [AutoMapper integration document](../../AutoMapper-Integration.md) for details. * `BookAppService` uses `IObjectMapper` to convert `Book` objects to `BookDto` objects and `CreateUpdateBookDto` objects to `Book` objects. The Startup template uses the [AutoMapper](http://automapper.org/) library as the object mapping provider. You defined the mappings before, so it will work as expected.
### Auto API Controllers ### Auto API Controllers
You normally create **Controllers** to expose application services as **HTTP API** endpoints. Thus allowing browser or 3rd-party clients to call them via AJAX. You normally create **Controllers** to expose application services as **HTTP API** endpoints. Thus allowing browser or 3rd-party clients to call them via AJAX. ABP can [**automagically**](../../AspNetCore/Auto-API-Controllers.md) configures your application services as MVC API Controllers by convention.
ABP can [**automagically**](../../AspNetCore/Auto-API-Controllers.md) configures your application services as MVC API Controllers by convention.
#### Swagger UI #### Swagger UI
The startup template is configured to run the [swagger UI](https://swagger.io/tools/swagger-ui/) using the [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) library. Run the application and enter `http://localhost:53929/swagger/` as URL on your browser. The startup template is configured to run the [swagger UI](https://swagger.io/tools/swagger-ui/) using the [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) library. Run the application and enter `https://localhost:XXXX/swagger/` (replace XXXX by your own port) as URL on your browser.
You will see some built-in service endpoints as well as the `Book` service and its REST-style endpoints: You will see some built-in service endpoints as well as the `Book` service and its REST-style endpoints:
![bookstore-swagger](images/bookstore-swagger.png) ![bookstore-swagger](images/bookstore-swagger.png)
Swagger has a nice UI to test APIs. You can try to execute the `[GET] /api/app/book` API to get a list of books.
### Dynamic JavaScript Proxies ### Dynamic JavaScript Proxies
It's common to call HTTP API endpoints via AJAX from the **JavaScript** side. You can use `$.ajax` or another tool to call the endpoints. However, ABP offers a better way. It's common to call HTTP API endpoints via AJAX from the **JavaScript** side. You can use `$.ajax` or another tool to call the endpoints. However, ABP offers a better way.
@ -266,7 +290,7 @@ ABP **dynamically** creates JavaScript **proxies** for all API endpoints. So, yo
#### Testing in the Browser Developer Console #### Testing in the Browser Developer Console
You can easily test the JavaScript proxy using your favorite browser's **Developer Console** now. Run the application again, open your browser's **developer tools** (shortcut: F12), switch to the **Console** tab, type the following code and press enter: You can easily test the JavaScript proxies using your favorite browser's **Developer Console** now. Run the application, open your browser's **developer tools** (shortcut: F12), switch to the **Console** tab, type the following code and press enter:
````js ````js
acme.bookStore.book.getList({}).done(function (result) { console.log(result); }); acme.bookStore.book.getList({}).done(function (result) { console.log(result); });
@ -275,7 +299,7 @@ acme.bookStore.book.getList({}).done(function (result) { console.log(result); })
* `acme.bookStore` is the namespace of the `BookAppService` converted to [camelCase](https://en.wikipedia.org/wiki/Camel_case). * `acme.bookStore` is the namespace of the `BookAppService` converted to [camelCase](https://en.wikipedia.org/wiki/Camel_case).
* `book` is the conventional name for the `BookAppService` (removed AppService postfix and converted to camelCase). * `book` is the conventional name for the `BookAppService` (removed AppService postfix and converted to camelCase).
* `getList` is the conventional name for the `GetListAsync` method defined in the `AsyncCrudAppService` base class (removed Async postfix and converted to camelCase). * `getList` is the conventional name for the `GetListAsync` method defined in the `AsyncCrudAppService` base class (removed Async postfix and converted to camelCase).
* `{}` argument is used to send an empty object to the `GetListAsync` method which normally expects an object of type `PagedAndSortedResultRequestDto` which is used to send paging and sorting options to the server. * `{}` argument is used to send an empty object to the `GetListAsync` method which normally expects an object of type `PagedAndSortedResultRequestDto` that is used to send paging and sorting options to the server (all properties are optional, so you can send an empty object).
* `getList` function returns a `promise`. So, you can pass a callback to the `done` (or `then`) function to get the result from the server. * `getList` function returns a `promise`. So, you can pass a callback to the `done` (or `then`) function to get the result from the server.
Running this code produces the following output: Running this code produces the following output:
@ -298,7 +322,7 @@ You should see a message in the console something like that:
successfully created the book with id: f3f03580-c1aa-d6a9-072d-39e75c69f5c7 successfully created the book with id: f3f03580-c1aa-d6a9-072d-39e75c69f5c7
```` ````
Check the `books` table in the database to see the new book row. You can try `get`, `update` and `delete` functions too. Check the `Books` table in the database to see the new book row. You can try `get`, `update` and `delete` functions yourself.
### Create the Books Page ### Create the Books Page
@ -306,20 +330,21 @@ It's time to create something visible and usable! Instead of classic MVC, we wil
Create a new `Books` folder under the `Pages` folder of the `Acme.BookStore.Web` project and add a new Razor Page named `Index.cshtml`: Create a new `Books` folder under the `Pages` folder of the `Acme.BookStore.Web` project and add a new Razor Page named `Index.cshtml`:
![bookstore-add-index-page](images/bookstore-add-index-page.png) ![bookstore-add-index-page](images/bookstore-add-index-page-v2.png)
Open the `Index.cshtml` and change the content as shown below: Open the `Index.cshtml` and change the content as shown below:
````html ````html
@page @page
@using Acme.BookStore.Pages.Books @using Acme.BookStore.Web.Pages.Books
@inherits Acme.BookStore.Pages.BookStorePageBase @inherits Acme.BookStore.Web.Pages.BookStorePageBase
@model IndexModel @model IndexModel
<h2>Books</h2> <h2>Books</h2>
```` ````
* Change the default inhertitance of the Razor View Page Model so it **inherits** from the `BookStorePageBase` class (instead of `PageModel`). The `BookStorePageBase` class which comes with the startup template and provides some shared properties/methods used by all pages. * This code changes the default inheritance of the Razor View Page Model so it **inherits** from the `BookStorePageBase` class (instead of `PageModel`). The `BookStorePageBase` class which comes with the startup template and provides some shared properties/methods used by all pages.
* Ensure that the `IndexModel` (*Index.cshtml.cs)* has the `Acme.BookStore.Pages.Books` namespace, or update it in the `Index.cshtml`.
#### Add Books Page to the Main Menu #### Add Books Page to the Main Menu
@ -334,17 +359,16 @@ context.Menu.AddItem(
#### Localizing the Menu Items #### Localizing the Menu Items
Localization texts are located under the `Localization/BookStore` folder of the `Acme.BookStore.Domain` project: Localization texts are located under the `Localization/BookStore` folder of the `Acme.BookStore.Domain.Shared` project:
![bookstore-localization-files](images/bookstore-localization-files.png) ![bookstore-localization-files](images/bookstore-localization-files-v2.png)
Open the `en.json` file and add localization texts for `Menu:BookStore` and `Menu:Books` keys: Open the `en.json` file and add localization texts for `Menu:BookStore` and `Menu:Books` keys to the end of the file:
````json ````json
{ {
"culture": "en", "culture": "en",
"texts": { "texts": {
//...
"Menu:BookStore": "Book Store", "Menu:BookStore": "Book Store",
"Menu:Books": "Books" "Menu:Books": "Books"
} }
@ -352,9 +376,9 @@ Open the `en.json` file and add localization texts for `Menu:BookStore` and `Men
```` ````
* ABP's localization system is built on [ASP.NET Core's standard localization](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) system and extends it in many ways. See the [localization document](../../Localization.md) for details. * ABP's localization system is built on [ASP.NET Core's standard localization](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) system and extends it in many ways. See the [localization document](../../Localization.md) for details.
* Localization key names are arbitrary, you can set any name. We prefer to add `Menu` namespace for menu items to distinguish from other texts. If a text is not defined in the localization file, it **fallbacks** to the localization key (ASP.NET Core's standard behavior). * Localization key names are arbitrary. You can set any name. We prefer to add `Menu:` prefix for menu items to distinguish from other texts. If a text is not defined in the localization file, it **fallbacks** to the localization key (ASP.NET Core's standard behavior).
Run the application and see the menu items are added to the top bar: Run the application and see the new menu item has been added to the top bar:
![bookstore-menu-items](images/bookstore-menu-items.png) ![bookstore-menu-items](images/bookstore-menu-items.png)
@ -362,17 +386,16 @@ When you click to the Books menu item, you are redirected to the new Books page.
#### Book List #### Book List
We will use the [Datatables.net](https://datatables.net/) JQuery plugin to show list of tables on the page. Datatables can completely work via AJAX, so it is fast and provides a good user experience. Datatables plugin is configured in the startup template, so you can directly use it in any page without including any style or script file to your page. We will use the [Datatables.net](https://datatables.net/) JQuery plugin to show list of tables on the page. Datatables can completely work via AJAX, it is fast and provides a good user experience. Datatables plugin is configured in the startup template, so you can directly use it in any page without including any style or script file to your page.
##### Index.cshtml Changes ##### Index.cshtml
Change the `Pages/Books/Index.cshtml` as following: Change the `Pages/Books/Index.cshtml` as following:
````html ````html
@page @page
@using Acme.BookStore.Pages.Books @inherits Acme.BookStore.Web.Pages.BookStorePageBase
@inherits Acme.BookStore.Pages.BookStorePageBase @model Acme.BookStore.Web.Pages.Books.IndexModel
@model IndexModel
@section scripts @section scripts
{ {
<abp-script src="/Pages/Books/index.js" /> <abp-script src="/Pages/Books/index.js" />
@ -405,7 +428,7 @@ Change the `Pages/Books/Index.cshtml` as following:
Create `index.js` JavaScript file under the `Pages/Books/` folder: Create `index.js` JavaScript file under the `Pages/Books/` folder:
![bookstore-index-js-file](images/bookstore-index-js-file.png) ![bookstore-index-js-file](images/bookstore-index-js-file-v2.png)
`index.js` content is shown below: `index.js` content is shown below:

68
docs/en/Tutorials/AspNetCore-Mvc/Part-II.md

@ -2,13 +2,13 @@
### About this Tutorial ### About this Tutorial
This is the second part of the tutorial series. See all parts: This is the second part of the ASP.NET Core MVC tutorial series. See all parts:
* [Part I: Create the project and a book list page](Part-I.md) * [Part I: Create the project and a book list page](Part-I.md)
* **Part II: Create, Update and Delete books (this tutorial)** * **Part II: Create, Update and Delete books (this tutorial)**
* [Part III: Integration Tests](Part-III.md) * [Part III: Integration Tests](Part-III.md)
You can download the **source code** of the application [from here](https://github.com/volosoft/abp/tree/master/samples/BookStore). You can access to the **source code** of the application from [the GitHub repository](https://github.com/volosoft/abp/tree/master/samples/BookStore).
### Creating a New Book ### Creating a New Book
@ -20,7 +20,7 @@ In this section, you will learn how to create a new modal dialog form to create
Create a new razor page, named `CreateModal.cshtml` under the `Pages/Books` folder of the `Acme.BookStore.Web` project: Create a new razor page, named `CreateModal.cshtml` under the `Pages/Books` folder of the `Acme.BookStore.Web` project:
![bookstore-add-create-dialog](images/bookstore-add-create-dialog.png) ![bookstore-add-create-dialog](images/bookstore-add-create-dialog-v2.png)
##### CreateModal.cshtml.cs ##### CreateModal.cshtml.cs
@ -30,7 +30,7 @@ Open the `CreateModal.cshtml.cs` file (`CreateModalModel` class) and replace wit
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Acme.BookStore.Pages.Books namespace Acme.BookStore.Web.Pages.Books
{ {
public class CreateModalModel : BookStorePageModelBase public class CreateModalModel : BookStorePageModelBase
{ {
@ -63,9 +63,9 @@ Open the `CreateModal.cshtml` file and paste the code below:
````html ````html
@page @page
@inherits Acme.BookStore.Pages.BookStorePageBase @inherits Acme.BookStore.Web.Pages.BookStorePageBase
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model Acme.BookStore.Pages.Books.CreateModalModel @model Acme.BookStore.Web.Pages.Books.CreateModalModel
@{ @{
Layout = null; Layout = null;
} }
@ -83,7 +83,7 @@ Open the `CreateModal.cshtml` file and paste the code below:
* This modal uses `abp-dynamic-form` tag helper to automatically create the form from the `CreateBookViewModel` class. * This modal uses `abp-dynamic-form` tag helper to automatically create the form from the `CreateBookViewModel` class.
* `abp-model` attribute indicates the model object, the `Book` property in this case. * `abp-model` attribute indicates the model object, the `Book` property in this case.
* `data-ajaxForm` attribute makes the form submitting via AJAX, instead of a classic page post. * `data-ajaxForm` attribute makes the form submitting via AJAX, instead of a classic page post.
* `abp-form-content` tag helper is a placeholder to render the form controls (this is optional and needed only if you added some other content in the `abp-dynamic-form` tag, just like in this view). * `abp-form-content` tag helper is a placeholder to render the form controls (this is optional and needed only if you added some other content in the `abp-dynamic-form` tag, just like in this page).
#### Add the "New book" Button #### Add the "New book" Button
@ -138,12 +138,12 @@ Create a new razor page, named `EditModal.cshtml` under the `Pages/Books` folder
Open the `EditModal.cshtml.cs` file (`EditModalModel` class) and replace with the following code: Open the `EditModal.cshtml.cs` file (`EditModalModel` class) and replace with the following code:
````C# ````csharp
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Acme.BookStore.Pages.Books namespace Acme.BookStore.Web.Pages.Books
{ {
public class EditModalModel : BookStorePageModelBase public class EditModalModel : BookStorePageModelBase
{ {
@ -153,7 +153,7 @@ namespace Acme.BookStore.Pages.Books
[BindProperty] [BindProperty]
public CreateUpdateBookDto Book { get; set; } public CreateUpdateBookDto Book { get; set; }
private readonly IBookAppService _bookAppService; private readonly IBookAppService _bookAppService;
public EditModalModel(IBookAppService bookAppService) public EditModalModel(IBookAppService bookAppService)
@ -180,38 +180,26 @@ namespace Acme.BookStore.Pages.Books
* Mapped `BookDto` (received from the `BookAppService.GetAsync`) to `CreateUpdateBookDto` in the `GetAsync` method. * Mapped `BookDto` (received from the `BookAppService.GetAsync`) to `CreateUpdateBookDto` in the `GetAsync` method.
* The `OnPostAsync` simply uses `BookAppService.UpdateAsync` to update the entity. * The `OnPostAsync` simply uses `BookAppService.UpdateAsync` to update the entity.
#### CreateUpdateBookDto #### BookDto to CreateUpdateBookDto Mapping
In order to perform `BookDto` to `CreateUpdateBookDto` object mapping, change the `CreateUpdateBookDto` class as shown below: In order to perform `BookDto` to `CreateUpdateBookDto` object mapping, open the `BookStoreWebAutoMapperProfile.cs` in the `Acme.BookStore.Web` project and change it as shown below:
````C# ````csharp
using System; using AutoMapper;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.AutoMapper;
namespace Acme.BookStore namespace Acme.BookStore.Web
{ {
[AutoMapTo(typeof(Book))] public class BookStoreWebAutoMapperProfile : Profile
[AutoMapFrom(typeof(BookDto))]
public class CreateUpdateBookDto
{ {
[Required] public BookStoreWebAutoMapperProfile()
[StringLength(128)] {
public string Name { get; set; } CreateMap<BookDto, CreateUpdateBookDto>();
}
[Required]
public BookType Type { get; set; } = BookType.Undefined;
[Required]
public DateTime PublishDate { get; set; }
[Required]
public float Price { get; set; }
} }
} }
```` ````
* Just added the `[AutoMapFrom(typeof(BookDto))]` attribute to create the mapping. * Just added `CreateMap<BookDto, CreateUpdateBookDto>();` as the mapping definition.
#### EditModal.cshtml #### EditModal.cshtml
@ -219,8 +207,8 @@ Replace `EditModal.cshtml` content with the following content:
````html ````html
@page @page
@inherits Acme.BookStore.Pages.BookStorePageBase @inherits Acme.BookStore.Web.Pages.BookStorePageBase
@using Acme.BookStore.Pages.Books @using Acme.BookStore.Web.Pages.Books
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model EditModalModel @model EditModalModel
@{ @{
@ -231,7 +219,7 @@ Replace `EditModal.cshtml` content with the following content:
<abp-modal-header title="@L["Update"].Value"></abp-modal-header> <abp-modal-header title="@L["Update"].Value"></abp-modal-header>
<abp-modal-body> <abp-modal-body>
<abp-input asp-for="Id" /> <abp-input asp-for="Id" />
<abp-form-content/> <abp-form-content />
</abp-modal-body> </abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer> <abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
</abp-modal> </abp-modal>
@ -240,7 +228,7 @@ Replace `EditModal.cshtml` content with the following content:
This page is very similar to the `CreateModal.cshtml` except; This page is very similar to the `CreateModal.cshtml` except;
* It includes an `abp-input` for the `Id` property to store id of the editing book. * It includes an `abp-input` for the `Id` property to store id of the editing book (which is a hidden input).
* It uses `Books/EditModal` as the post URL and *Update* text as the modal header. * It uses `Books/EditModal` as the post URL and *Update* text as the modal header.
#### Add "Actions" Dropdown to the Table #### Add "Actions" Dropdown to the Table
@ -420,6 +408,12 @@ $(function () {
}); });
```` ````
Open the `en.json` in the `Acme.BookStore.Domain.Shared` project and add the following line:
````json
"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?"
````
Run the application and try to delete a book. Run the application and try to delete a book.
### Next Part ### Next Part

87
docs/en/Tutorials/AspNetCore-Mvc/Part-III.md

@ -2,22 +2,21 @@
### About this Tutorial ### About this Tutorial
This is the third part of the tutorial series. See all parts: This is the third part of the ASP.NET Core MVC tutorial series. See all parts:
- [Part I: Create the project and a book list page](Part-I.md) - [Part I: Create the project and a book list page](Part-I.md)
- [Part II: Create, Update and Delete books](Part-II.md) - [Part II: Create, Update and Delete books](Part-II.md)
- **Part III: Integration Tests (this tutorial)** - **Part III: Integration Tests (this tutorial)**
You can download the **source code** of the application [from here](https://github.com/volosoft/abp/tree/master/samples/BookStore). You can access to the **source code** of the application from [the GitHub repository](https://github.com/volosoft/abp/tree/master/samples/BookStore).
### Test Projects in the Solution ### Test Projects in the Solution
There are two test projects in the solution: There are multiple test projects in the solution:
* `Acme.BookStore.Application.Tests` is for unit & integration tests. You can write tests for application service methods. It uses **EF Core SQLite in-memory** database. ![bookstore-test-projects-v2](images/bookstore-test-projects-v2.png)
* `Acme.BookStore.Web.Tests` is for full stack integration tests including the web layer. So, you can write tests for UI pages too.
Test projects use the following libraries for testing: Each project is used to test the related application project. Test projects use the following libraries for testing:
* [xunit](https://xunit.github.io/) as the main test framework. * [xunit](https://xunit.github.io/) as the main test framework.
* [Shoudly](http://shouldly.readthedocs.io/en/latest/) as an assertion library. * [Shoudly](http://shouldly.readthedocs.io/en/latest/) as an assertion library.
@ -25,79 +24,40 @@ Test projects use the following libraries for testing:
### Adding Test Data ### Adding Test Data
Startup template contains the `BookStoreTestDataBuilder` class in the `Acme.BookStore.Application.Tests` project that creates some data to run tests on. It's shown below: Startup template contains the `BookStoreTestDataSeedContributor` class in the `Acme.BookStore.TestBase` project that creates some data to run tests on.
````C# Change the `BookStoreTestDataSeedContributor` class as show below:
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.Threading;
namespace Acme.BookStore
{
public class BookStoreTestDataBuilder : ITransientDependency
{
private readonly IIdentityDataSeeder _identityDataSeeder;
public BookStoreTestDataBuilder(IIdentityDataSeeder identityDataSeeder)
{
_identityDataSeeder = identityDataSeeder;
}
public void Build()
{
AsyncHelper.RunSync(BuildInternalAsync);
}
public async Task BuildInternalAsync()
{
await _identityDataSeeder.SeedAsync("1q2w3E*");
}
}
}
````
* It simply uses `IIdentityDataSeeder` which is implemented by the identity module and creates an admin role and admin user. You can use them in your tests.
* You can add new test data in the `BuildInternalAsync` method.
Change the `BookStoreTestDataBuilder` class as show below:
````C# ````C#
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity; using Volo.Abp.Guids;
using Volo.Abp.Threading;
namespace Acme.BookStore namespace Acme.BookStore
{ {
public class BookStoreTestDataBuilder : ITransientDependency public class BookStoreTestDataSeedContributor
: IDataSeedContributor, ITransientDependency
{ {
private readonly IIdentityDataSeeder _identityDataSeeder;
private readonly IRepository<Book, Guid> _bookRepository; private readonly IRepository<Book, Guid> _bookRepository;
private readonly IGuidGenerator _guidGenerator;
public BookStoreTestDataBuilder( public BookStoreTestDataSeedContributor(
IIdentityDataSeeder identityDataSeeder, IRepository<Book, Guid> bookRepository,
IRepository<Book, Guid> bookRepository) IGuidGenerator guidGenerator)
{ {
_identityDataSeeder = identityDataSeeder;
_bookRepository = bookRepository; _bookRepository = bookRepository;
_guidGenerator = guidGenerator;
} }
public void Build() public async Task SeedAsync(DataSeedContext context)
{
AsyncHelper.RunSync(BuildInternalAsync);
}
public async Task BuildInternalAsync()
{ {
await _identityDataSeeder.SeedAsync("1q2w3E*");
await _bookRepository.InsertAsync( await _bookRepository.InsertAsync(
new Book new Book
{ {
Id = Guid.NewGuid(), Id = _guidGenerator.Create(),
Name = "Test book 1", Name = "Test book 1",
Type = BookType.Fantastic, Type = BookType.Fantastic,
PublishDate = new DateTime(2015, 05, 24), PublishDate = new DateTime(2015, 05, 24),
@ -108,7 +68,7 @@ namespace Acme.BookStore
await _bookRepository.InsertAsync( await _bookRepository.InsertAsync(
new Book new Book
{ {
Id = Guid.NewGuid(), Id = _guidGenerator.Create(),
Name = "Test book 2", Name = "Test book 2",
Type = BookType.Science, Type = BookType.Science,
PublishDate = new DateTime(2014, 02, 11), PublishDate = new DateTime(2014, 02, 11),
@ -120,7 +80,8 @@ namespace Acme.BookStore
} }
```` ````
* Injected `IRepository<Book, Guid>` and used it in the `BuildInternalAsync` to create two book entities. * Injected `IRepository<Book, Guid>` and used it in the `SeedAsync` to create two book entities as the test data.
* Used `IGuidGenerator` service to create GUIDs. While `Guid.NewGuid()` would perfectly work for testing, `IGuidGenerator` has additional features especially important while using real databases (see the [Guid generation document](../../Guid-Generation.md) for more).
### Testing the BookAppService ### Testing the BookAppService
@ -210,6 +171,8 @@ public async Task Should_Not_Create_A_Book_Without_Name()
* Since the `Name` is empty, ABP throws an `AbpValidationException`. * Since the `Name` is empty, ABP throws an `AbpValidationException`.
### Testing Web Pages Open the **Test Explorer Window** (use Test -> Windows -> Test Explorer menu if it is not visible) and **Run All** tests:
![bookstore-appservice-tests](images/bookstore-appservice-tests.png)
TODO Congratulations, green icons show that tests have been successfully passed!

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-appservice-tests.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-test-projects-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-test-projects.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

3
docs/en/Value-Objects.md

@ -0,0 +1,3 @@
## Value Objects
TODO

6
docs/en/docs-nav.json

@ -41,6 +41,10 @@
} }
] ]
}, },
{
"text": "CLI",
"path": "CLI.md"
},
{ {
"text": "Fundamentals", "text": "Fundamentals",
"items": [ "items": [
@ -214,7 +218,7 @@
}, },
{ {
"text": "Tag Helpers", "text": "Tag Helpers",
"path": "Tag-Helpers.md" "path": "AspNetCore/Tag-Helpers/Index.md"
}, },
{ {
"text": "Theming", "text": "Theming",

BIN
docs/en/images/bookstore-user-management-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/en/images/bookstore-user-management.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/en/images/bookstore-visual-studio-solution-tiered.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/en/images/bookstore-visual-studio-solution-v2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

BIN
docs/en/images/bookstore-visual-studio-solution-v3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/en/images/bookstore-visual-studio-solution.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

BIN
docs/en/images/db-migrator-app.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/en/images/disable-package-restore-visual-studio.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/images/issuemanagement-module-solution.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/en/images/layered-project-dependencies-module.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/en/images/layered-project-dependencies.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
docs/en/images/tiered-solution-applications.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/en/images/tiered-solution-servers.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

6
docs/zh-Hans/AspNetCore/Auto-API-Controllers.md

@ -2,7 +2,7 @@
创建[应用程序服务](Application-Services.md)后, 通常需要创建API控制器以将此服务公开为HTTP(REST)API端点. 典型的API控制器除了将方法调用重定向到应用程序服务并使用[HttpGet],[HttpPost],[Route]等属性配置REST API之外什么都不做. 创建[应用程序服务](Application-Services.md)后, 通常需要创建API控制器以将此服务公开为HTTP(REST)API端点. 典型的API控制器除了将方法调用重定向到应用程序服务并使用[HttpGet],[HttpPost],[Route]等属性配置REST API之外什么都不做.
ABP可以按照惯例 **自动** 将你的应用程序服务配置为MVC API控制器. 大多数时候你不关心它的详细配置,但它可以完全被自定义. ABP可以按照惯例 **自动** 将你的应用程序服务配置为API控制器. 大多数时候你不关心它的详细配置,但它可以完全被自定义.
## 配置 ## 配置
@ -16,7 +16,9 @@ public class BookStoreWebModule : AbpModule
{ {
Configure<AbpAspNetCoreMvcOptions>(options => Configure<AbpAspNetCoreMvcOptions>(options =>
{ {
options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly); options
.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly);
}); });
} }
} }

136
docs/zh-Hans/CLI.md

@ -0,0 +1,136 @@
# ABP CLI
ABP CLI (命令行接口) 是一个命令行工具,用来执行基于ABP解决方案的一些常见操作.
## Installation
ABP CLI 是一个 [dotnet global tool](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools). 使用命令行窗口安装:
````bash
dotnet tool install -g Volo.Abp.Cli
````
更新最新版本:
````bash
dotnet tool update -g Volo.Abp.Cli
````
## Commands
### new
生成基于ABP[启动模板](Startup-Templates/Index.md)的新解决方案.
基本用法:
````bash
abp new <解决方案名称> [options]
````
示例:
````bash
abp new Acme.BookStore
````
* Acme.BookStore是解决方案的名称.
* 常见的命名方式类似于 *YourCompany.YourProject*. 不过你可以使用自己喜欢的方式,如 *YourProject* (单级命名空间) 或 *YourCompany.YourProduct.YourModule* (三级命名空间).
#### Options
* `--template` 或 `-t`: 指定模板. 默认的模板是 `mvc`.可用的模板有:
* `mvc` (默认): ASP.NET Core [MVC应用程序模板](Startup-Templates/Mvc.md). 其他选项:
* `--database-provider` 或 `-d`: 指定数据库提供程序. 默认提供程序是 `ef`. 可用的提供程序有:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
* `--tiered`: 创建分层解决方案,Web和Http Api层在物理上是分开的. 如果未指定会创建一个分层的解决方案, 此解决方案没有那么复杂,适合大多数场景.
* `mvc-module`: ASP.NET Core [MVC模块模板](Startup-Templates/Mvc-Module.md). 其他选项:
* `--no-ui`: 不包含UI. 仅创建服务模块 (也称为微服务 - 没有UI).
* `--output-folder` 或 `-o`: 指定输出文件夹,默认是当前目录.
### add-package
添加新的ABP包到项目中
* 添加nuget包做为项目的依赖项目.
* 添加 `[DependsOn(...)]` attribute到项目的模块类 (请参阅 [模块开发文档](Module-Development-Basics.md)).
> 需要注意的是添加的模块可能需要额外的配置,通常会在包的文档中指出.
基本用法:
````bash
abp add-package <包名> [options]
````
示例:
````
abp add-package Volo.Abp.MongoDB
````
* 示例中将Volo.Abp.MongoDB包添加到项目中.
#### Options
* `--project` 或 `-p`: 指定项目 (.csproj) 路径. 如果未指定,Cli会尝试在当前目录查找.csproj文件.
### add-module
通过查找模块的所有包,查找解决方案中的相关项目,并将每个包添加到解决方案中的相应项目,从而将多包模块添加到解决方案中.
> 由于分层,不同的数据库提供程序选项或其他原因,业务模块通常由多个包组成. 使用`add-module`命令可以大大简化向模块添加模块的过程. 但是每个模块可能需要一些其他配置,这些配置通常在相关模块的文档中指出.
基本用法:
````bash
abp add-module <模块名称> [options]
````
示例:
```bash
abp add-module Volo.Blogging
```
* 示例中将Volo.Blogging模块添加到解决方案中.
#### Options
* `--solution` 或 `-s`: 指定解决方案 (.sln) 路径. 如果未指定,CLI会尝试在当前目录中寻找.sln文件.
* `--skip-db-migrations`: 对于EF Core 数据库提供程序,它会自动添加新代码的第一次迁移 (`Add-Migration`) 并且在需要时更新数据库 (`Update-Database`). 指定此选项可跳过此操作.
### update
更新所有ABP相关的包可能会很繁琐,框架和模块都有很多包. 此命令自动将解决方案或项目中所有ABP相关的包更新到最新版本.
用法:
````bash
abp update [options]
````
* 如果你的文件夹中有.sln文件,运行命令会将解决方案中所有项目ABP相关的包更新到最新版本.
* 如果你的文件夹中有.csproj文件,运行命令会将项目中所有ABP相关的包更新到最新版本.
#### Options
* `--include-previews` 或 `-p`: 将预览版, 测试版本 和 rc 包 同时更新到最新版本.
### help
CLI的基本用法信息.
用法:
````bash
abp help [命令名]
````
示例:
````bash
abp help # 显示常规帮助.
abp help new # 显示有关 "New" 命令的帮助.
````

38
docs/zh-Hans/Contribution/Localization-Text-Files.md

@ -2,19 +2,39 @@
这是一个来自框架的本地化文本文件列表, 任何人都可以做出贡献. 我们会将此列表保持最新: 这是一个来自框架的本地化文本文件列表, 任何人都可以做出贡献. 我们会将此列表保持最新:
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json * https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json * https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json
* https://github.com/abpframework/abp/tree/master/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/en.json * https://github.com/abpframework/abp/tree/master/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Web/Localization/Resources/Blogging/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json * https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json * https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Web/Localization/Resources/Blogging/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json * https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Web/Localization/Resources/Docs/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Localization/Resources/FeatureManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Localization/ApplicationContracts/en.json * https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json
* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Localization/Resources/AbpPermissionManagement/en.json * https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Localization/Resources/AbpPermissionManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Localization/Resources/AbpTenantManagement/Web/en.json * https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Localization/Resources/AbpSettingManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/Localization/ApplicationContracts/en.json * https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc/src/MyCompanyName.MyProjectName.Domain/Localization/MyProjectName/en.json * https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Localization/Resources/AbpTenantManagement/Web/en.json
* https://github.com/abpframework/abp/tree/master/templates/module/src/MyCompanyName.MyProjectName.Domain/MyCompanyName/MyProjectName/Localization/Domain/en.json * https://github.com/abpframework/abp/tree/master/samples/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json
* https://github.com/abpframework/abp/tree/master/templates/module/src/MyCompanyName.MyProjectName.Web/Localization/Resources/MyProjectName/en.json * https://github.com/abpframework/abp/tree/master/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/en.json
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Application.Contracts/Localization/MyProjectName/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/DomainShared/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Web/Localization/MyProjectName/Web/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json

3
docs/zh-Hans/Data-Seeding.md

@ -0,0 +1,3 @@
# Data Seeding
TODO

3
docs/zh-Hans/Dynamic-JavaScript-API-Clients.md

@ -0,0 +1,3 @@
## Dynamic JavaScript API Clients
TODO

71
docs/zh-Hans/Getting-Started-AspNetCore-MVC-Template.md

@ -1,38 +1,43 @@
## ASP.NET Core MVC 模板 ## ASP.NET Core MVC 模板入门
### 创建新项目 ### 创建新项目
访问[模板创建页面](https://abp.io/Templates), 输入项目名称并创建项目, 如下所示: 本教程使用 **ABP CLI** 创建一个新项目. 更多选项, 请参阅[入门](https://cn.abp.io/get-started)页面.
![bookstore-create--template](images/bookstore-create-template.png) 如果你之前未安装,请使用命令行安装ABP CLI:
单击 *create* 按钮时,将使用你提供的名称创建一个新的Visual Studio解决方案并开始下载. ````bash
dotnet tool install -g Volo.Abp.Cli
````
在空文件夹中使用 `abp new` 命令来创建项目:
````
abp new Acme.BookStore
````
> 你可以使用不同级别的命名空间; 例如BookStore, Acme.BookStore或Acme.Retail.BookStore.
`new` 命令创建**分层MVC应用程序**, **Entity Framework Core**作为数据库提供程序. 但是,它还有其他选择. 有关所有可用选项,请参见[CLI文档](CLI.md)
#### 预先要求 #### 预先要求
下载的项目需要: 创建项目的要求:
* [Visual Studio 2017 (v15.9.0+)](https://visualstudio.microsoft.com/tr/downloads/) * [Visual Studio 2017 (v15.9.0+)](https://visualstudio.microsoft.com/tr/downloads/)
* [.NET Core 2.1.1+](https://www.microsoft.com/net/download/dotnet-core/) * [.NET Core 2.2+](https://www.microsoft.com/net/download/dotnet-core/)
### 解决方案结构 ### 解决方案结构
下载后解压文件并在 **Visual Studio 2017(15.7.0 +)** 中打开: 在**Visual Studio**中打开解决方案:
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v2.png)
该解决方案具有分层结构(基于域驱动设计), 其中:
* ``.Domain`` 为领域层. ![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v3.png)
* ``.Application`` 为应用层.
* ``.Web`` 为是表示层.
* ``.EntityFrameworkCore`` 是EF Core集成.
EF Core 数据库迁移被分离到名为`.EntityFrameworkCore.DbMigrations`项目中. 该解决方案具有分层结构(基于[Domain Driven Design](Domain-Driven-Design.md)), 并包含配置好的的单元&集成测试项目,可与**EF Core**和**SQLite**数据库内存一起使用.
解决方案还包含配置好的的单元&集成测试项目, 以便与 **EF Core** 和 **SQLite内存中** 数据库配合使用. > 请参阅[MVC应用程序模板文档](Startup-Templates/Mvc.md)以详细了解解决方案结构.
### 创建数据库 ### 数据库连接字符串
查看`.Web`项目下`appsettings.json`文件中的 **连接字符串**: 查看`.Web`项目下`appsettings.json`文件中的 **连接字符串**:
@ -44,9 +49,29 @@ EF Core 数据库迁移被分离到名为`.EntityFrameworkCore.DbMigrations`项
} }
```` ````
解决方案使用 **Entity Framework Core** 和 **MS SQL Server**. EF Core支持[各种](https://docs.microsoft.com/en-us/ef/core/providers/)数据库提供程序,因此你可以根据实际需要使用其他DBMS. 解决方案使用 **Entity Framework Core** 和 **MS SQL Server**. EF Core支持[各种](https://docs.microsoft.com/en-us/ef/core/providers/)数据库提供程序,因此你可以根据实际需要使用其他DBMS. 如果需要,请更改连接字符串.
### 创建数据库并应用数据库迁移
你有两个选项来创建数据库.
右键单击`.Web`项目并**设置启动项目** #### 使用DbMigrator应用程序
该解决方案包含一个控制台应用程序(在此示例中名为`Acme.BookStore.DbMigrator`),可以创建数据库,应用迁移和初始化数据. 它对开发和生产环境都很有用.
> `.DbMigrator`项目有自己的`appsettings.json`. 因此,如果你更改了上面的连接字符串,则还应更改此字符串.
右键单击`.DbMigrator`项目并选择 **设置为启动项目**:
![set-as-startup-project](images/set-as-startup-project.png)
按F5(或Ctrl + F5)运行应用程序. 它将具有如下所示的输出:
![set-as-startup-project](images/db-migrator-app.png)
#### 使用EF Core Update-Database命令
Ef Core具有`Update-Database`命令, 可根据需要创建数据库并应用挂起的迁移. 右键单击`.Web`项目并选择**设置为启动项目**:
![set-as-startup-project](images/set-as-startup-project.png) ![set-as-startup-project](images/set-as-startup-project.png)
@ -56,6 +81,8 @@ EF Core 数据库迁移被分离到名为`.EntityFrameworkCore.DbMigrations`项
这将基于配置的连接字符串创建新数据库. 这将基于配置的连接字符串创建新数据库.
> 使用`.Migrator`工具是建议的方法, 因为它还能初始化初始数据能够正确运行Web应用程序.
### 运行应用程序 ### 运行应用程序
你现在可以运行应用程序,它将会打开**home**页面: 你现在可以运行应用程序,它将会打开**home**页面:
@ -64,9 +91,9 @@ EF Core 数据库迁移被分离到名为`.EntityFrameworkCore.DbMigrations`项
单击 **登录** 按钮, 输入用户名`admin`, 密码`1q2w3E*`, 登录应用程序. 单击 **登录** 按钮, 输入用户名`admin`, 密码`1q2w3E*`, 登录应用程序.
启动模板包括 **身份管理(identity management)** 模块. 登录后将提供身份管理菜单,你可以在其中管理**角色**,**用户**及其**权限**. 启动模板包括**身份管理**和**租户管理**模块. 登录后,将显示"管理"菜单, 你可以在其中管理**租户**,**角色**,**用户**和**权限**. 用户管理页面如下所示:
![bookstore-user-management](images/bookstore-user-management.png) ![bookstore-user-management](images/bookstore-user-management-v2.png)
### 下一步是什么? ### 下一步是什么?

2
docs/zh-Hans/Getting-Started-Console-Application.md

@ -1,4 +1,4 @@
## 使用Console Application ## 在控制台应用中使用ABP
本教程将介绍如何从头开始以最小的依赖关系启动ABP. 你通常希望以 **[启动模板](https://abp.io/Templates)** 开头. 本教程将介绍如何从头开始以最小的依赖关系启动ABP. 你通常希望以 **[启动模板](https://abp.io/Templates)** 开头.

92
docs/zh-Hans/Index.md

@ -1,68 +1,32 @@
# ABP 文档 # ABP 文档
> 翻译来自[cnAbp](https://github.com/cnabp)组织,中文网会持续跟进翻译,目前Abp vNext的英文文档还未完成,大家对整体框架没有深入的理解,翻译难免存在一些问题.敬请见谅.😀 > 中文文档翻译来自[cnAbp](https://github.com/cnabp)组织,Abp中文网会持续跟进翻译,目前Abp vNext的英文文档还未完成,大家对整体框架没有深入的理解,翻译难免存在一些问题.敬请见谅.😀
## 目录 ABP是一个**开源应用程序框架**,专注于基于ASP.NET Core的Web应用程序开发,但也支持开发其他类型的应用程序.
* 入门 浏览左侧导航菜单以深入了解文档.
* 从启动模板开始
* [ASP.NET Core MVC 模板](Getting-Started-AspNetCore-MVC-Template.md) ## 项目状态
* 从空项目开始
* [使用Console Application](Getting-Started-Console-Application.md) ABP是开源[ASP.NET Boilerplate](https://aspnetboilerplate.com/)框架的**下一代框架**, 它目前处于早期预览阶段,尚未准备好在生产中使用. 文档仍在进行中,远未完成.
* [使用 ASP.NET Core Web Application](Getting-Started-AspNetCore-Application.md)
* 教程 对于短期和生产级应用程序, 建议使用[ASP.NET Boilerplate](https://aspnetboilerplate.com/)框架,该框架具有丰富的功能集,成熟,积极维护和最新.
* 应用开发
* [使用 ASP.NET Core MVC](Tutorials/AspNetCore-Mvc/Part-I.md) ## 入门
* 基础知识
* [依赖注入](Dependency-Injection.md) 使用ABP开发新项目的最简单方法是使用启动模板:
* AutoFac 集成
* [虚拟文件系统](Virtual-File-System.md) * [ASP.NET Core MVC 模板](Getting-Started-AspNetCore-MVC-Template.md)
* [本地化](Localization.md)
* [异常处理](Exception-Handling.md) 如果您想从头开始(使用空项目),请手动安装ABP框架并使用以下教程:
* 验证
* 授权 * [控制台应用程序](Getting-Started-Console-Application.md)
* 缓存 * [ASP.NET Core Web 应用程序](Getting-Started-AspNetCore-Application.md)
* 审计
* 设置管理 ## 源码
* 对象映射
* AutoMapper 集成 ABP托管在GitHub上, 参见[源代码](https://github.com/abpframework/abp).
* 事件
* 本地 Event Bus ## 贡献代码
* 分布式 Event Bus
* RabbitMQ 集成 ABP是一个社区驱动的开源项目.如果你想成为该项目的一部分,请参阅[贡献指南](Contribution/Index.md).
* 服务
* 对象序列化
* JSON序列化
* 邮件
* GUIDs
* 线程
* 定时
* [多租户](Multi-Tenancy.md)
* 模块开发
* [基础](Module-Development-Basics.md)
* 模块插件
* [最佳实践](Best-Practices/Index.md)
* 领域驱动设计
* 领域层
* [实体&聚合根](Entities.md)
* 值对象
* [仓储](Repositories.md)
* 领域服务
* 规约
* 应用服务层
* 应用服务
* 数据传输对象(DTO)
* 工作单元
* ASP.NET Core MVC
* API 版本控制
* 用户界面
* [客户端包管理](AspNetCore/Client-Side-Package-Management.md)
* [捆绑&压缩](AspNetCore/Bundling-Minification.md)
* [Tag Helpers](Tag-Helpers.md)
* [主题](AspNetCore/Theming.md)
* 后台服务
* [后台作业](Background-Jobs.md)
* 数据访问
* [Entity Framework Core 集成](Entity-Framework-Core.md)
* [MongoDB 集成](MongoDB.md)
* 测试

8
docs/zh-Hans/Startup-Templates/Index.md

@ -0,0 +1,8 @@
# 启动模板
虽然你可以从一个空项目开始并手动添加所需的包,但启动模板可以非常轻松,舒适地使用ABP框架启动新的解决方案.
单击下面列表中的名称以查看相关启动模板的文档:
* [**mvc**](Mvc.md): ASP.NET Core MVC应用程序模板.
* [**mvc-module**](Mvc-Module.md): ASP.NET Core MVC模块/服务模板.

6
docs/zh-Hans/Startup-Templates/Mvc-Module.md

@ -0,0 +1,6 @@
# MVC Module 启动模板
TODO

259
docs/zh-Hans/Startup-Templates/Mvc.md

@ -0,0 +1,259 @@
# MVC应用程序启动模板
## 介绍
MVC应用程序启动模板是基于[领域驱动设计](../Domain-Driven-Design.md)(DDD)分层(或根据偏好分层)的应用程序结构.
在这篇文档中详细介绍了解决方案结构和项目
* 参阅[ASP.NET Core MVC 模板入门](../Getting-Started-AspNetCore-MVC-Template.md)创建此模板的新解决方案并运行它.
* 参阅[ASP.NET Core MVC 教程](../Tutorials/AspNetCore-Mvc/Part-I.md)学习使用此模板开发应用程序.
## 如何开始
你要以使用[ABP CLI](../CLI.md)创建基于此启动模板的新项目,或者你也可以在[入门](https://abp.io/get-started)页面创建并下载项目. 在这里我们使用CLI创建新项目.
如果未安装ABP CLI,第一步是安装ABP CLI
````bash
dotnet tool install -g Volo.Abp.Cli
````
然后使用 `abp new` 命令在空文件夹中创建新解决方案:
````bash
abp new Acme.BookStore -t mvc
````
* `Acme.BookStore` 是解决方案的名称, 如*YourCompany.YourProduct*. 你可以使用单级或多级名称.
* 示例中指定了启动模板 (`-t` 或 `--template` 选项). 不过 `mvc` 是默认模板,即使未指定也会创建 `MVC` 的模板项目.
### 指定数据库提供程序
`MVC`模板支持以下数据库提供程序:
- `ef`: Entity Framework Core (默认)
- `mongodb`: MongoDB
使用 `-d` (或 `--database-provider`) 选项指定数据库提供程序:
````bash
abp new Acme.BookStore -d mongodb
````
### 创建分层解决方案
使用 `--tiered` 选项创建分层解决方案, Web与WebApi层在物理上是分开的. 如果未指定,CLI会创建一个分层的解决方案,这个解决方案没有那么复杂,适合大多数场景.
````bash
abp new Acme.BookStore --tiered
````
有关分层的方法,请参阅下面的"分层结构"部分.
## 解决方案结构
根据命令的选项,会创建略有不同的解决方案结构.
### 默认结构
如果未指定选项,你会得到如下所示的解决方案:
![bookstore-visual-studio-solution-v3](../images/bookstore-visual-studio-solution-v3.png)
项目组织在`src`和`test`文件夹中. `src`文件夹包含实际应用程序,该应用程序基于前面提到的[DDD](../Domain-Driven-Design.md)原则进行分层. 下图展示了解决方案的层和项目的依赖关系:
![layered-project-dependencies](../images/layered-project-dependencies.png)
下面介绍解决方案中的项目及依赖关系.
#### .Domain.Shared 项目
项目包含常量,枚举和其他对象,这些对象实际上是领域层的一部分,但是解决方案中所有的层/项目中都会使用到.
例如 `BookType` 枚举和 `BookConts` 类 (可能是 `Book` 实体用到的常数字段,像`MaxNameLength`)都适合放在这个项目中.
* 该项目不依赖解决方案中的其他项目. 其他项目直接或间接依赖该项目
#### .Domain 项目
解决方案的领域层. 它主要包含 [实体, 集合根](../Entities.md), [领域服务](../Domain-Services.md), [值类型](../Value-Types.md), [仓储接口](../Repositories.md) 和解决方案的其他领域对象.
例如 `Book` 实体和 `IBookRepository` 接口都适合放在这个项目中.
* 它依赖 `.Domain.Shared` 项目,因为项目中会用到它的一些常量,枚举和定义其他对象.
#### .Application.Contracts 项目
项目主要包含 [应用服务](../Application-Services.md) **interfaces** 和应用层的 [数据传输对象](../Data-Transfer-Objects.md) (DTO). 它用于分离应用层的接口和实现. 这种方式可以将接口项目做为约定包共享给客户端.
* 它依赖 `.Domain.Shared` 因为它可能会在应用接口和DTO中使用常量,枚举和其他的共享对象.
#### .Application 项目
项目包含 `.Application.Contracts` 项目的 [应用服务](../Application-Services.md) 接口**实现**.
* 它依赖 `.Application.Contracts` 项目, 因为它需要实现接口与使用DTO.
* 它依赖 `.Domain` 项目,因为它需要使用领域对象(实体,仓储接口等)执行应用程序逻辑.
#### .EntityFrameworkCore 项目
这是集成EF Core的项目. 它定义了 `DbContext` 并实现 `.Domain` 项目中定义的仓储接口.
* 它依赖 `.Domain` 项目,因为它需要引用实体和仓储接口.
> 只有在你使用了EF Core做为数据库提供程序时,此项目才会可用. 如果选择的是其他数据库提供程序那么项目的名称会改变
#### .EntityFrameworkCore.DbMigrations 项目
包含解决方案的EF Core数据库迁移. 它有独立的 `DbContext` 来专门管理迁移.
ABP是一个模块化的框架,理想的设计是让每个模块都有自己的 `DbContext` 类. 这时用于迁移的 `DbContext` 就会发挥作用. 它将所有的 `DbContext` 配置统一到单个模型中以维护单个数据库的模式. 对于更高级的场景,可以程序可以拥有多个数据库(每个数据库有一个或多个模块表)和多个迁移`DbContext`(每个都维护不同的数据库模式)
需要注意,迁移 `DbContext` 仅用于数据库迁移,而不在*运行时*使用.
* 它依赖 `.EntityFrameworkCore` 项目,因为它重用了应用程序的 `DbContext` 配置 .
> 只有在你使用了EF Core做为数据库提供程序时,此项目才会可用.
#### .DbMigrator 项目
这是一个控制台应用唾弃,它简化了在开发和生产环境执行数据库迁移的操作.当你使用它时;
* 必要时创建数据库(没有数据库时).
* 应用未迁移的数据库迁移.
* 初始化种子数据(当你需要时).
> 这个项目有自己的 `appsettings.json` 文件. 所以如果要更改数据库连接字符串,请记得也要更改此文件.
初始化种子数据很很要,ABP具有模块化的种子数据基础设施. 种子数据的更多信息,请参阅[文档](../Data-Seeding.md).
虽然创建数据库和应用迁移似乎只对关系数据库有用,但即使您选择NoSQL数据库提供程序(如MongoDB),也会生成此项目. 这时,它会为应用程序提供必要的初始数据.
* 它依赖 `.EntityFrameworkCore.DbMigrations` 项目 (针对EF Core),因为它需要访问迁移文件.
* 它依赖 `.Application.Contracts` 项目,因为它需要访问权限定义在初始化种子数据时为管理员用户赋予所有权限.
#### .HttpApi 项目
用于定义API控制器.
大多数情况下,你不需要手动定义API控制器,因为ABP的[动态API](../AspNetCore/Auto-API-Controllers.md)功能会根据你的应用层自动创建API控制器. 但是,如果你需要编写API控制器,那么它是最合适的地方.
* 它依赖 `.Application.Contracts` 项目,因为它需要注入应用服务接口.
#### .HttpApi.Client 项目
定义C#客户端代理使用解决方案的HTTP API项目. 可以将上编辑共享给第三方客户端,使其轻松的在DotNet应用程序中使用你的HTTP API(其他类型的应用程序可以手动或使用其平台的工具来使用你的API).
ABP有[动态 C# API 客户端](../AspNetCore/Dynamic-CSharp-API-Clients.md)功能,所以大多数情况下你不需要手动的创建C#客户端代理.
`.HttpApi.Client.ConsoleTestApp` 项目是一个用于演示客户端代理用法的控制台应用程序.
* 它依赖 `.Application.Contracts` 项目,因为它需要使用应用服务接口和DTO.
> 如果你不需要为API创建动态C#客户端代理,可以删除此项目和依赖项
#### .Web 项目
包含应用程序的用户界面(UI). 包括Razor页面,javascript文件,样式文件,图片等...
包含应用程序主要的 `appsettings.json` 配置文件,用于配置数据库连接字符串和应用程序的其他配置
* 依赖 `.HttpApi` 项目,因为UI层需要使用解决方案的API和应用服务接口.
> 如果查看 `.Web.csproj` 源码, 你会看到对 `.Application` 和 `.EntityFrameworkCore.DbMigrations` 项目的引用.
>
> 在编写UI层时实际上不需要这些引用. 因为UI层通常不依赖于EF Core或应用层的实现. 这个启动模板已经为分层部署做好了准备,API层托管在不同与UI层的服务器中.
>
> 但是如果你不选择 `--tiered` 选项, .Web项目会有这些引用,以便能够将Web,Api和应用层托管在单个应用程序站点.
>
> 你可以在表示层中使用领域实体和仓储,但是根据DDD的理论,这被认为是一种不好的做法.
#### 测试项目
解决方案有多个测试项目,每一层都会有一个:
* `.Domain.Tests` 用于测试领域层.
* `.Application.Tests` 用于测试应用层.
* `.EntityFrameworkCore.Tests` 用于测试EF Core配置与自定义仓储.
* `.Web.Tests` 用于测试UI.
* `.TestBase` 所有测试项目的基础(共享)项目.
此外, `.HttpApi.Client.ConsoleTestApp` 是一个控制台应用程序(不是自动化测试项目),它用于演示DotNet应用程序中HTTP API的用法.
测试项目已为集成测试做好准备:
* 它完成集成到ABP框架和应用程序的所有服务.
* 如果数据库提供程序是EF Core,测试项目会使用SQLite内存数据库,如果是MongoDB,它使用[Mongo2Go](https://github.com/Mongo2Go/Mongo2Go)库.
* 授权被禁用,任何的应用服务都可以在测试中轻松调用.
你依然可以编写单元测试,只不过它很难写(因为你需要准备mock/fake对象),但它的运行速度更快(因为只测试单个类并跳过所有初始化过程).
#### 如何运行?
设置`.Web`为启动项目. 默认用户名 `admin`, 密码 `1q2w3E*`.
更多信息请参阅[ASP.NET Core MVC 模板入门](../Getting-Started-AspNetCore-MVC-Template.md).
### 分层结构
如果你按上面的描述指定了 `--tiered` 选项,会创建分层解决方案. 分层结构的目的是**将Web应用程序和HTTP API部署到不同的服务器**:
![bookstore-visual-studio-solution-v3](../images/tiered-solution-servers.png)
* 浏览器渲染HTML,执行CSS和JavaScript来运行UI.
* Web服务器托管静态文件(CSS,JavaScript,图片...等)和动态组件(如Razor页面),它通过HTTP请求到API服务器执行应用程序的业务逻辑.
* API服务器托管HTTP API,使用应用程序的应用层和领域层执行业务逻辑.
* 最后数据库服务器托管数据库.
与之前默认结构的三层部署比较,分层解决方案允许四层部署.
> 除非你真的需要四层部署,一般建议采用默认结构,它更易于开发,部署和维护.
解决方案结构如下所示:
![bookstore-visual-studio-solution-v3](../images/bookstore-visual-studio-solution-tiered.png)
与默认结构不同,我们得到了两个新项目: `.IdentityServer` 和 `.HttpApi.Host`.
#### .IdentityServer 项目
用于其他项目的身份验证服务器. `.Web`项目使用OpenId Connect身份验证获取当前用户的身份和访问令牌. 然后使用访问令牌调用HTTP API服务器. HTTP API服务器使用bearer token从访问令牌获取声明授权当前用户.
![bookstore-visual-studio-solution-v3](../images/tiered-solution-applications.png)
ABP使用开源的[IdentityServer4](https://identityserver.io/)框架做应用程序间的身份验证. 有关IdentityServer4和OpenId Connect协议的详细信息请参阅[IdentityServer4文档](http://docs.identityserver.io).
它有自己的`appsettings.json`文件(数据库连接字符串等其他配置).
#### .HttpApi.Host 项目
该项目是一个承载解决方案API的应用程序.
它有自己的`appsettings.json`文件(数据库连接字符串等其他配置).
#### .Web 项目
与默认结构一样,包含应用程序的用户界面(UI). 包括Razor页面,javascript文件,样式文件,图片等...
项目包含`appsetting.json`文件,但没有连接字符串配置, 它不需要连接到数据库. 文件中主要包含远程API服务器端点和身份验证服务器
#### 前置条件
* [Redis](https://redis.io/): 应用程序使用Redis做分布式缓存,你需要安装并运行Redis.
#### 如何运行?
你应该按照以下顺序运行应用:
* 首先运行`.IdentityServer`,因为其他应用程序依赖它做身份验证.
* 然后运行`.HttpApi.Server`,因为`.Web`应用程序需要访问HTTI API.
* 最后运行`.Web`并登录到应用程序(用户名: `admin` 密码: `1q2w3E*`).
### 其他数据库提供程序
TODO
#### MongoDB
TODO

142
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md

@ -2,7 +2,7 @@
### 关于本教程 ### 关于本教程
本教程中,你会创建一个用于管理书籍和书籍作者的程序.会用到 **Entity Framework Core** (EF Core)作为ORM([启动模板](https://abp.io/Templates)中预配置的ORM). 在本系列教程中, 你将构建一个用于管理书籍及其作者列表的应用程序. **Entity Framework Core**(EF Core)将用作ORM提供者,因为它是默认数据库提供者.
这是本教程所有章节中的第一章,下面是所有的章节: 这是本教程所有章节中的第一章,下面是所有的章节:
@ -10,35 +10,37 @@
- [Part II: 创建,编辑,删除书籍](Part-II.md) - [Part II: 创建,编辑,删除书籍](Part-II.md)
- [Part III: 集成测试](Part-III.md) - [Part III: 集成测试](Part-III.md)
你可以从[这里](https://github.com/volosoft/abp/tree/master/samples/BookStore)下载本程序的源码. 你可以从[GitHub存储库](https://github.com/volosoft/abp/tree/master/samples/BookStore)访问应用程序的**源代码**.
### 创建项目 ### 创建项目
打开[启动模板页](https://abp.io/Templates)并下载一个新的项目叫做`Acme.BookStore`.根据[模板文档](../../Getting-Started-AspNetCore-MVC-Template.md)创建数据库并运行这个程序. 创建一个名为`Acme.BookStore`的新项目, 创建数据库并按照[入门文档](../../Getting-Started-AspNetCore-MVC-Template.md)运行应用程序.
### 解决方案的结构 ### 解决方案的结构
下面的图片展示了从启动模板创建的项目是如何分层的. 下面的图片展示了从启动模板创建的项目是如何分层的.
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v2.png) ![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v3.png)
> 你可以查看[MVC应用程序模板文档](../../Startup-Templates/Mvc.md)以详细了解解决方案结构.但是,你将通过本教程了解基础知识.
### 创建Book实体 ### 创建Book实体
在 **领域层** 定义[实体](../../Entities.md)(`Acme.BookStore.Domain` 项目中).这个项目最主要的实体就是`Book`: 启动模板中的域层分为两个项目:
- `Acme.BookStore.Domain`包含你的[实体](../../Entities.md), [领域服务](../../Domain-Services.md)和其他核心域对象.
- `Acme.BookStore.Domain.Shared`包含可与客户共享的常量,枚举或其他域相关对象.
在解决方案的**领域层**(`Acme.BookStore.Domain`项目)中定义[实体](../../Entities.md). 该应用程序的主要实体是`Book`. 在`Acme.BookStore.Domain`项目中创建一个名为`Book`的类,如下所示:
````C# ````C#
using System; using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore namespace Acme.BookStore
{ {
[Table("Books")]
public class Book : AuditedAggregateRoot<Guid> public class Book : AuditedAggregateRoot<Guid>
{ {
[Required]
[StringLength(128)]
public string Name { get; set; } public string Name { get; set; }
public BookType Type { get; set; } public BookType Type { get; set; }
@ -50,8 +52,8 @@ namespace Acme.BookStore
} }
```` ````
* ABP有两个基本的实体基类: `AggregateRoot` 和 `Entity`.**Aggregate Root**是 **领域驱动设计(DDD)** 的概念之一.更多信息和最佳实践请查看[实体文档](../../Entities.md). * ABP为实体提供了两个基本的基类: `AggregateRoot`和`Entity`. **Aggregate Root**是**域驱动设计(DDD)** 概念之一. 有关详细信息和最佳做法,请参阅[实体文档](../../Entities.md).
* `Book`实体继承了`AuditedAggregateRoot`,`AuditedAggregateRoot`类在`AggregateRoot`类的基础上添加了一些审计属性(`CreationTime`, `CreatorId`, `LastModificationTime`... 等.). * `Book`实体继承了`AuditedAggregateRoot`,`AuditedAggregateRoot`类在`AggregateRoot`类的基础上添加了一些审计属性(`CreationTime`, `CreatorId`, `LastModificationTime` 等).
* `Guid`是`Book`实体的主键类型. * `Guid`是`Book`实体的主键类型.
* 使用 **数据注解** 为EF Core添加映射.或者你也可以使用 EF Core 自带的[fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling). * 使用 **数据注解** 为EF Core添加映射.或者你也可以使用 EF Core 自带的[fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling).
@ -62,10 +64,10 @@ namespace Acme.BookStore
````C# ````C#
namespace Acme.BookStore namespace Acme.BookStore
{ {
public enum BookType : byte public enum BookType
{ {
Undefined, Undefined,
Advanture, Adventure,
Biography, Biography,
Dystopia, Dystopia,
Fantastic, Fantastic,
@ -91,14 +93,15 @@ public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
#### 配置你的Book实体 #### 配置你的Book实体
从`Acme.BookStore.EntityFrameworkCore` 项目中打开 BookStoreDbContextModelCreatingExtensions.cs 文件, 在 ConfigureBookStore 方法最后添加如下代码来配置Book实体: 在`Acme.BookStore.EntityFrameworkCore`项目中打开`BookStoreDbContextModelCreatingExtensions.cs`文件,并将以下代码添加到`ConfigureBookStore`方法的末尾以配置Book实体:
````C# ````C#
builder.Entity<Book>(b => builder.Entity<Book>(b =>
{ {
b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema); b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema);
b.ConfigureExtraProperties(); b.ConfigureAuditedAggregateRoot(); //auto configure for the base class props
}); b.Property(x => x.Name).IsRequired().HasMaxLength(128);
});
```` ````
#### 添加新的Migration并更新数据库 #### 添加新的Migration并更新数据库
@ -115,26 +118,27 @@ PM> Update-Database
#### 添加示例数据 #### 添加示例数据
`Update-Database`命令会在数据库中创建`Books`表.打开这个表添加几行数据,然后就可以把这些数据展示到页面上: `Update-Database`命令在数据库中创建了`AppBooks`表. 打开数据库并输入几个示例行,以便在页面上显示它们:
![bookstore-books-table](images/bookstore-books-table.png) ![bookstore-books-table](images/bookstore-books-table.png)
### 创建应用服务 ### 创建应用服务
下一步是创建[应用服务](../../Application-Services.md)来管理(创建,列出,更新,删除...)书籍. 下一步是创建[应用服务](../../Application-Services.md)来管理(创建,列出,更新,删除)书籍. 启动模板中的应用程序层分为两个项目:
* `Acme.BookStore.Application.Contracts`主要包含你的DTO和应用程序服务接口.
* `Acme.BookStore.Application`包含应用程序服务的实现.
#### BookDto #### BookDto
在`Acme.BookStore.Application`项目中添加一个名为`BookDto`的DTO类: 在`Acme.BookStore.Application.Contracts`项目中创建一个名为`BookDto`的DTO类:
````C# ````C#
using System; using System;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.AutoMapper;
namespace Acme.BookStore namespace Acme.BookStore
{ {
[AutoMapFrom(typeof(Book))]
public class BookDto : AuditedEntityDto<Guid> public class BookDto : AuditedEntityDto<Guid>
{ {
public string Name { get; set; } public string Name { get; set; }
@ -151,7 +155,23 @@ namespace Acme.BookStore
* **DTO**类被用来在 **表示层** 和 **应用层** **传递数据**.查看[DTO文档](../../Data-Transfer-Objects.md)查看更多信息. * **DTO**类被用来在 **表示层** 和 **应用层** **传递数据**.查看[DTO文档](../../Data-Transfer-Objects.md)查看更多信息.
* 为了在页面上展示书籍信息,`BookDto`被用来将书籍数据传递到表示层. * 为了在页面上展示书籍信息,`BookDto`被用来将书籍数据传递到表示层.
* `BookDto`继承自 `AuditedEntityDto<Guid>`.跟上面定义的`Book`类一样具有一些审计属性. * `BookDto`继承自 `AuditedEntityDto<Guid>`.跟上面定义的`Book`类一样具有一些审计属性.
* `[AutoMapFrom(typeof(Book))]`用来创建从`Book`类到`BookDto`的AutoMapper映射.使用这种方法.你可以将`Book`对象自动转换成`BookDto`对象(而不是手动复制所有的属性).
在将书籍返回到表示层时,需要将`Book`实体转换为`BookDto`对象. [AutoMapper](https://automapper.org)库可以在定义了正确的映射时自动执行此转换. 启动模板配置了AutoMapper,因此你只需在`Acme.BookStore.Application`项目的`BookStoreApplicationAutoMapperProfile`类中定义映射:
````csharp
using AutoMapper;
namespace Acme.BookStore
{
public class BookStoreApplicationAutoMapperProfile : Profile
{
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
}
}
}
````
#### CreateUpdateBookDto #### CreateUpdateBookDto
@ -184,11 +204,17 @@ namespace Acme.BookStore
```` ````
* 这个DTO类被用于在创建或更新书籍的时候从用户界面获取图书信息. * 这个DTO类被用于在创建或更新书籍的时候从用户界面获取图书信息.
* 类中的属性定义了数据注解(如`[Required]`)用来定义有效性验证.ABP会自动校验DTO的数据有效性. * 它定义了数据注释属性(如`[Required]`)来定义属性的验证. DTO由ABP框架[自动验证](../../Validation.md).
就像上面的`BookDto`一样,创建一个从`CreateUpdateBookDto`对象到`Book`实体的映射:
````csharp
CreateMap<CreateUpdateBookDto, Book>();
````
#### IBookAppService #### IBookAppService
为应用服务定义一个名为 `IBookAppService` 的接口: 在`Acme.BookStore.Application.Contracts`项目中定义一个名为`IBookAppService`的接口:
````C# ````C#
using System; using System;
@ -210,15 +236,14 @@ namespace Acme.BookStore
} }
```` ````
* 为应用服务定义接口不是必须的,不过,这是推荐的最佳实践. * 框架定义应用程序服务的接口<u>不是必需的</u>. 但是,它被建议作为最佳实践.
* `IAsyncCrudAppService`中定义了基础的 **CRUD**方法:`GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync` 和 `DeleteAsync`.不需要扩展它.取而代之,你可以继承空的`IApplicationService`接口定义你自己的方法. * `IAsyncCrudAppService`定义了常见的**CRUD**方法:`GetAsync`,`GetListAsync`,`CreateAsync`,`UpdateAsync`和`DeleteAsync`. 你可以从空的`IApplicationService`接口继承并手动定义自己的方法.
* `IAsyncCrudAppService`有一些变体,你可以为每一个方法使用单个或者多个的DTO.(译者注:意思是类似EntityDto和UpdateEntityDto可以用同一个,也可以分别单独指定 * `IAsyncCrudAppService`有一些变体, 你可以在每个方法中使用单独的DTO,也可以分别单独指定.
)
#### BookAppService #### BookAppService
创建 `BookAppService` 并实现 `IBookAppService`接口: 在`Acme.BookStore.Application`项目中实现名为`BookAppService`的`IBookAppService`:
````C# ````C#
using System; using System;
@ -243,23 +268,23 @@ namespace Acme.BookStore
```` ````
* `BookAppService`继承了`AsyncCrudAppService<...>`.`AsyncCrudAppService<...>`实现了上面定义的CRUD方法. * `BookAppService`继承了`AsyncCrudAppService<...>`.`AsyncCrudAppService<...>`实现了上面定义的CRUD方法.
* `BookAppService`注入了`IRepository<Book, Guid>`,`IRepository<Book, Guid>`是默认为`Book`创建的仓储.ABP会自动为每一个聚合根(或实体)创建仓储.参考[仓储文档](../../Repositories.md). * `BookAppService`注入`IRepository <Book,Guid>`,这是`Book`实体的默认仓储. ABP自动为每个聚合根(或实体)创建默认仓储. 请参阅[仓储文档](../../Repositories.md)
* `BookAppService`使用了 `IObjectMapper` 将`Book`转换成`BookDto`,将`CreateUpdateBookDto`转换成`Book`.启动模板中使用了[AutoMapper](http://automapper.org/)作为对象映射提供程序.你可以像上面那样使用`AutoMapFrom` 和 `AutoMapTo`定义映射.查看[AutoMapper集成文档](../../AutoMapper-Integration.md)获取更多信息. * `BookAppService`使用`IObjectMapper`将`Book`对象转换为`BookDto`对象, 将`CreateUpdateBookDto`对象转换为`Book`对象. 启动模板使用[AutoMapper](http://automapper.org/)库作为对象映射提供程序. 你之前定义了映射, 因此它将按预期工作.
### 自动生成API Controllers ### 自动生成API Controllers
你通常需要创建 **Controllers** 将应用服务暴露为 **HTTP API**.这样浏览器或第三方客户端可以通过AJAX的方式访问它们. 你通常创建**Controller**以将应用程序服务公开为**HTTP API**端点. 因此允许浏览器或第三方客户端通过AJAX调用它们. ABP可以[**自动**](../../AspNetCore/Auto-API-Controllers.md)按照惯例将你的应用程序服务配置为MVC API控制器.
ABP可以通过约定[**自动**](../../AspNetCore/Auto-API-Controllers.md)将应用服务转换成MVC API Controllers.
#### Swagger UI #### Swagger UI
启动模板使用了[Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore)库配置了[swagger UI](https://swagger.io/tools/swagger-ui/).运行程序并在浏览器中输入`http://localhost:53929/swagger/`. 启动模板配置为使用[Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore)运行[swagger UI](https://swagger.io/tools/swagger-ui/). 运行应用程序并在浏览器中输入`https://localhost:XXXX/swagger/`(用您自己的端口替换XXXX)作为URL.
你会看到一些内置的接口和`Book`的接口,它们都是REST风格的: 你会看到一些内置的接口和`Book`的接口,它们都是REST风格的:
![bookstore-swagger](images/bookstore-swagger.png) ![bookstore-swagger](images/bookstore-swagger.png)
Swagger有一个很好的UI来测试API. 你可以尝试执行`[GET] /api/app/book` API来获取书籍列表.
### 动态JavaScript代理 ### 动态JavaScript代理
在Javascript端通过AJAX的方式调用HTTP API接口是很常见的,你可以使用`$.ajax`或这其他的工具来调用接口.当然,ABP中提供了更好的方式. 在Javascript端通过AJAX的方式调用HTTP API接口是很常见的,你可以使用`$.ajax`或这其他的工具来调用接口.当然,ABP中提供了更好的方式.
@ -270,6 +295,8 @@ ABP **自动** 为所有的API接口创建了JavaScript **代理**.因此,你可
你可以使用你钟爱的浏览器的 **开发者控制台** 中轻松测试JavaScript代理.运行程序,并打开浏览器的 **开发者工具**(快捷键:F12),切换到 **Console** 标签,输入下面的代码并回车: 你可以使用你钟爱的浏览器的 **开发者控制台** 中轻松测试JavaScript代理.运行程序,并打开浏览器的 **开发者工具**(快捷键:F12),切换到 **Console** 标签,输入下面的代码并回车:
你现在可以使用自己喜欢的浏览器的**开发者控制台**轻松测试JavaScript代理. 运行应用程序, 打开浏览器的**开发者工具**(快捷键:F12),切换到**Console**选项卡,输入以下代码并按回车键.
````js ````js
acme.bookStore.book.getList({}).done(function (result) { console.log(result); }); acme.bookStore.book.getList({}).done(function (result) { console.log(result); });
```` ````
@ -277,7 +304,7 @@ acme.bookStore.book.getList({}).done(function (result) { console.log(result); })
* `acme.bookStore`是`BookAppService`的命名空间,转换成了[驼峰命名](https://en.wikipedia.org/wiki/Camel_case). * `acme.bookStore`是`BookAppService`的命名空间,转换成了[驼峰命名](https://en.wikipedia.org/wiki/Camel_case).
* `book`是`BookAppService`转换后的名字(去除了AppService后缀并转成了驼峰命名). * `book`是`BookAppService`转换后的名字(去除了AppService后缀并转成了驼峰命名).
* `getList`是定义在`AsyncCrudAppService`基类中的`GetListAsync`方法转换后的名字(去除了Async后缀并转成了驼峰命名). * `getList`是定义在`AsyncCrudAppService`基类中的`GetListAsync`方法转换后的名字(去除了Async后缀并转成了驼峰命名).
* `{}`参数用来传递一个空的对象给`GetListAsync`方法.GetListAsync期望的参数是`PagedAndSortedResultRequestDto`类型的对象,`PagedAndSortedResultRequestDto`类型中定义了分页和排序选项. * `{}`参数用于将空对象发送到`GetListAsync`方法,该方法通常需要一个类型为`PagedAndSortedResultRequestDto`的对象,用于向服务器发送分页和排序选项(所有属性都是可选的,所以你可以发送一个空对象).
* `getList`方法返回了一个`promise`.因此,你可以传递一个回调函数到`done`(或者`then`)方法中来获取服务返回的结果. * `getList`方法返回了一个`promise`.因此,你可以传递一个回调函数到`done`(或者`then`)方法中来获取服务返回的结果.
运行这段代码会产生下面的输出: 运行这段代码会产生下面的输出:
@ -300,7 +327,7 @@ acme.bookStore.book.create({ name: 'Foundation', type: 7, publishDate: '1951-05-
successfully created the book with id: f3f03580-c1aa-d6a9-072d-39e75c69f5c7 successfully created the book with id: f3f03580-c1aa-d6a9-072d-39e75c69f5c7
```` ````
检查数据库表`books`中的数据,你会发现多了一行新数据,你也可以尝试`get`, `update` 和 `delete`方法. 检查数据库中的`Books`表以查看新书. 你可以自己尝试`get`,`update`和`delete`功能.
### 创建书籍页面 ### 创建书籍页面
@ -309,20 +336,21 @@ successfully created the book with id: f3f03580-c1aa-d6a9-072d-39e75c69f5c7
在 `Acme.BookStore.Web`项目的`Pages`文件夹下创建一个新的文件夹叫`Books`并添加一个名为`Index.cshtml`的Razor Page. 在 `Acme.BookStore.Web`项目的`Pages`文件夹下创建一个新的文件夹叫`Books`并添加一个名为`Index.cshtml`的Razor Page.
![bookstore-add-index-page](images/bookstore-add-index-page.png) ![bookstore-add-index-page](images/bookstore-add-index-page-v2.png)
打开`Index.cshtml`并把内容修改成下面这样: 打开`Index.cshtml`并把内容修改成下面这样:
````html ````html
@page @page
@using Acme.BookStore.Pages.Books @using Acme.BookStore.Web.Pages.Books
@inherits Acme.BookStore.Pages.BookStorePageBase @inherits Acme.BookStore.Web.Pages.BookStorePageBase
@model IndexModel @model IndexModel
<h2>Books</h2> <h2>Books</h2>
```` ````
* 修改Razor View Page Model的默认继承,使页面 **继承** 自`BookStorePageBase`类(代替`PageModel`).`BookStorePageBase`类来自于启动模板,它提供了一些公开的可以被所有的页面使用的属性/方法. * 此代码更改了Razor View Page Model的默认继承,因此它从`BookStorePageBase`类(而不是`PageModel`)继承.启动模板附带的`BookStorePageBase`类,提供所有页面使用的一些共享属性/方法.
* 确保`IndexModel`(Index.cshtml.cs)具有`Acme.BookStore.Pages.Books`命名空间,或者在`Index.cshtml`中更新它.
#### 将Books页面添加到主菜单 #### 将Books页面添加到主菜单
@ -337,17 +365,16 @@ context.Menu.AddItem(
#### 本地化菜单 #### 本地化菜单
本地化的文本在`Acme.BookStore.Domain`项目的`Localization/BookStore`文件夹中. 本地化文本位于`Acme.BookStore.Domain.Shared`项目的`Localization/BookStore`文件夹下:
![bookstore-localization-files](images/bookstore-localization-files.png) ![bookstore-localization-files](images/bookstore-localization-files-v2.png)
打开`en.json`文件,为`Menu:BookStore` 和 `Menu:Books`添加本地化文本: 打开`en.json`文件,将`Menu:BookStore`和`Menu:Books`键的本地化文本添加到文件末尾:
````json ````json
{ {
"culture": "en", "culture": "en",
"texts": { "texts": {
//...
"Menu:BookStore": "Book Store", "Menu:BookStore": "Book Store",
"Menu:Books": "Books" "Menu:Books": "Books"
} }
@ -355,9 +382,9 @@ context.Menu.AddItem(
```` ````
* ABP的本地化功能建立在[ASP.NET Core's standard localization]((https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization))之上并增加了一些扩展.查看[本地化文档](../../Localization.md). * ABP的本地化功能建立在[ASP.NET Core's standard localization]((https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization))之上并增加了一些扩展.查看[本地化文档](../../Localization.md).
* 本地化中key的名字是随便定义的,你可以随意命名.我们喜欢为菜单添加`Menu`命名空间,以区别于其他的文本.如果文本没有在本地化文件中定义,就会 **返回** 本地的化的key(ASP.NET Core的标准做法). * 本地化key是任意的. 你可以设置任何名称. 我们更喜欢为菜单项添加`Menu:`前缀以区别于其他文本. 如果未在本地化文件中定义文本,则它将**返回**到本地化的key(ASP.NET Core的标准行为).
运行程序就会看到菜单已经添加到了顶部: 运行该应用程序,看到新菜单项已添加到顶部栏:
![bookstore-menu-items](images/bookstore-menu-items.png) ![bookstore-menu-items](images/bookstore-menu-items.png)
@ -365,17 +392,16 @@ context.Menu.AddItem(
#### 书籍列表 #### 书籍列表
我们会在页面上使用JQuery插件[Datatables.net](https://datatables.net/)来展示列表.Datatables可以完全通过AJAX工作,所以它很快而且有良好的用户体验.启动模板中已经配置好了Datatables插件,因此你可以在你的页面中直接使用,不需要引用样式和脚本文件. 我们将使用[Datatables.net](https://datatables.net/)JQuery插件来显示页面上的表格列表. 数据表可以完全通过AJAX工作,速度快,并提供良好的用户体验. Datatables插件在启动模板中配置,因此你可以直接在任何页面中使用它,而需要在页面中引用样式和脚本文件.
##### 修改Index.cshtml ##### Index.cshtml
将`Pages/Books/Index.cshtml`改成下面的样子: 将`Pages/Books/Index.cshtml`改成下面的样子:
````html ````html
@page @page
@using Acme.BookStore.Pages.Books @inherits Acme.BookStore.Web.Pages.BookStorePageBase
@inherits Acme.BookStore.Pages.BookStorePageBase @model Acme.BookStore.Web.Pages.Books.IndexModel
@model IndexModel
@section scripts @section scripts
{ {
<abp-script src="/Pages/Books/index.js" /> <abp-script src="/Pages/Books/index.js" />
@ -408,7 +434,7 @@ context.Menu.AddItem(
在`Pages/Books/`文件夹中创建 `index.js`文件 在`Pages/Books/`文件夹中创建 `index.js`文件
![bookstore-index-js-file](images/bookstore-index-js-file.png) ![bookstore-index-js-file](images/bookstore-index-js-file-v2.png)
`index.js`的内容如下: `index.js`的内容如下:
@ -430,7 +456,7 @@ $(function () {
* `abp.libs.datatables.createAjax`是帮助ABP的动态JavaScript API代理跟Datatable的格式相适应的辅助方法. * `abp.libs.datatables.createAjax`是帮助ABP的动态JavaScript API代理跟Datatable的格式相适应的辅助方法.
* `abp.libs.datatables.normalizeConfiguration`是另一个辅助方法.不是必须的, 但是它通过为缺少的选项提供常规值来简化数据表配置. * `abp.libs.datatables.normalizeConfiguration`是另一个辅助方法.不是必须的, 但是它通过为缺少的选项提供常规值来简化数据表配置.
* `acme.bookStore.book.getList`是获取书籍列表的方法(上面已经介绍过了) * `acme.bookStore.book.getList`是获取书籍列表的方法(上面已经介绍过了)
* 查看 [Datatable's 文档](https://datatables.net/manual/) 了解更多配置项. * 查看 [Datatable文档](https://datatables.net/manual/) 了解更多配置项.
最终的页面如下: 最终的页面如下:

66
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md

@ -2,13 +2,13 @@
### 关于本教程 ### 关于本教程
这是本教程所有章节中的第二章.下面是所有的章节: 这是ASP.NET Core MVC教程系列的第二章. 查看其它章节
* [Part I: 创建项目和书籍列表页面](Part-I.md) * [Part I: 创建项目和书籍列表页面](Part-I.md)
* **Part II: 创建,编辑,删除书籍(本章)** * **Part II: 创建,编辑,删除书籍(本章)**
* [Part III: 集成测试](Part-III.md) * [Part III: 集成测试](Part-III.md)
你可以从 [这里](https://github.com/volosoft/abp/tree/master/samples/BookStore) 下载本程序的**源码**. 你可以从[GitHub存储库](https://github.com/volosoft/abp/tree/master/samples/BookStore)访问应用程序的**源代码**.
### 新增 Book 实体 ### 新增 Book 实体
@ -20,7 +20,7 @@
在 `Acme.BookStore.Web` 项目的 `Pages/Books` 目录下新建一个 `CreateModal.cshtml` Razor页面: 在 `Acme.BookStore.Web` 项目的 `Pages/Books` 目录下新建一个 `CreateModal.cshtml` Razor页面:
![bookstore-add-create-dialog](images/bookstore-add-create-dialog.png) ![bookstore-add-create-dialog](images/bookstore-add-create-dialog-v2.png)
##### CreateModal.cshtml.cs ##### CreateModal.cshtml.cs
@ -30,7 +30,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Acme.BookStore.Pages.Books namespace Acme.BookStore.Web.Pages.Books
{ {
public class CreateModalModel : BookStorePageModelBase public class CreateModalModel : BookStorePageModelBase
{ {
@ -63,9 +63,9 @@ namespace Acme.BookStore.Pages.Books
````html ````html
@page @page
@inherits Acme.BookStore.Pages.BookStorePageBase @inherits Acme.BookStore.Web.Pages.BookStorePageBase
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model Acme.BookStore.Pages.Books.CreateModalModel @model Acme.BookStore.Web.Pages.Books.CreateModalModel
@{ @{
Layout = null; Layout = null;
} }
@ -138,12 +138,12 @@ $('#NewBookButton').click(function (e) {
展开 `EditModal.cshtml`,打开 `EditModal.cshtml.cs` 文件( `EditModalModel` 类) 并替换成以下代码: 展开 `EditModal.cshtml`,打开 `EditModal.cshtml.cs` 文件( `EditModalModel` 类) 并替换成以下代码:
````C# ````csharp
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Acme.BookStore.Pages.Books namespace Acme.BookStore.Web.Pages.Books
{ {
public class EditModalModel : BookStorePageModelBase public class EditModalModel : BookStorePageModelBase
{ {
@ -180,38 +180,26 @@ namespace Acme.BookStore.Pages.Books
* 在 `OnGetAsync` 方法中,将 `BookAppService.GetAsync` 方法返回的 `BookDto` 映射成 `CreateUpdateBookDto` 并赋值给Book属性. * 在 `OnGetAsync` 方法中,将 `BookAppService.GetAsync` 方法返回的 `BookDto` 映射成 `CreateUpdateBookDto` 并赋值给Book属性.
* `OnPostAsync` 方法直接使用 `BookAppService.UpdateAsync` 来更新实体. * `OnPostAsync` 方法直接使用 `BookAppService.UpdateAsync` 来更新实体.
#### CreateUpdateBookDto #### BookDto到CreateUpdateBookDto对象映射
为了执行从 `BookDto` 到 `CreateUpdateBookDto` 的对象映射, 按如下所示修改 `CreateUpdateBookDto`类: 为了执行`BookDto`到`CreateUpdateBookDto`对象映射,请打开`Acme.BookStore.Web`项目中的`BookStoreWebAutoMapperProfile.cs`并更改它,如下所示:
````C# ````csharp
using System; using AutoMapper;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.AutoMapper;
namespace Acme.BookStore namespace Acme.BookStore.Web
{ {
[AutoMapTo(typeof(Book))] public class BookStoreWebAutoMapperProfile : Profile
[AutoMapFrom(typeof(BookDto))]
public class CreateUpdateBookDto
{ {
[Required] public BookStoreWebAutoMapperProfile()
[StringLength(128)] {
public string Name { get; set; } CreateMap<BookDto, CreateUpdateBookDto>();
}
[Required]
public BookType Type { get; set; } = BookType.Undefined;
[Required]
public DateTime PublishDate { get; set; }
[Required]
public float Price { get; set; }
} }
} }
```` ````
* 仅添加 `[AutoMapFrom(typeof(BookDto))]` 特性就可以创建上述映射关系. * 刚刚添加了`CreateMap<BookDto, CreateUpdateBookDto>();`作为映射定义.
#### EditModal.cshtml #### EditModal.cshtml
@ -219,8 +207,8 @@ namespace Acme.BookStore
````html ````html
@page @page
@inherits Acme.BookStore.Pages.BookStorePageBase @inherits Acme.BookStore.Web.Pages.BookStorePageBase
@using Acme.BookStore.Pages.Books @using Acme.BookStore.Web.Pages.Books
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model EditModalModel @model EditModalModel
@{ @{
@ -231,7 +219,7 @@ namespace Acme.BookStore
<abp-modal-header title="@L["Update"].Value"></abp-modal-header> <abp-modal-header title="@L["Update"].Value"></abp-modal-header>
<abp-modal-body> <abp-modal-body>
<abp-input asp-for="Id" /> <abp-input asp-for="Id" />
<abp-form-content/> <abp-form-content />
</abp-modal-body> </abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer> <abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
</abp-modal> </abp-modal>
@ -240,8 +228,8 @@ namespace Acme.BookStore
这个页面内容和 `CreateModal.cshtml` 非常相似,除了以下几点: 这个页面内容和 `CreateModal.cshtml` 非常相似,除了以下几点:
* 此页面包含了一个 `abp-input` 以保存所编辑book实体的 `Id` 属性值. * 它包含`id`属性的`abp-input`, 用于存储编辑书的id(它是隐藏的Input)
* 此页面指定的post地址是 `Books/EditModal` ,并用文本 *Update* 作为 modal 标题. * 此页面指定的post地址是`Books/EditModal`, 并用文本 *Update* 作为 modal 标题.
#### 为表格添加 "操作(Actions)" 下拉菜单 #### 为表格添加 "操作(Actions)" 下拉菜单
@ -420,6 +408,12 @@ $(function () {
}); });
```` ````
打开`Acme.BookStore.Domain.Shared`项目中的`en.json`并添加以下行:
````json
"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?"
````
运行程序并尝试删除一个book实体. 运行程序并尝试删除一个book实体.
### 下一章 ### 下一章

89
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md

@ -2,23 +2,21 @@
### 关于本教程 ### 关于本教程
这是本教程所有章节中的第三章.下面是所有的章节: 这是ASP.NET Core MVC教程系列的第三章. 查看其它章节
- [Part I: 创建项目和书籍列表页面](Part-I.md) - [Part I: 创建项目和书籍列表页面](Part-I.md)
- [Part II: 创建,编辑,删除书籍](Part-II.md) - [Part II: 创建,编辑,删除书籍](Part-II.md)
- **Part III: 集成测试(本章)** - **Part III: 集成测试(本章)**
你可以从 [这里](https://github.com/volosoft/abp/tree/master/samples/BookStore) 下载本程序的**源码**. 你可以从[GitHub存储库](https://github.com/volosoft/abp/tree/master/samples/BookStore)访问应用程序的**源代码**.
### 解决方案中的测试项目 ### 解决方案中的测试项目
本解决方案中有两个测试项目: 解决方案中有多个测试项目:
![bookstore-test-projects-v2](images/bookstore-test-projects-v2.png)
* `Acme.BookStore.Application.Tests` 项目用于单元测试和集成测试.你可以在这个项目中为Application Service方法写测试代码.这个项目使用了 **EF Core SQLite in-memory** 数据库. 每个项目用于测试相关的应用程序项目.测试项目使用以下库进行测试:
* `Acme.BookStore.Web.Tests` 项目用于包含Web层的完整集成测试.所以,你也可以在这里写关于UI页面的测试.
测试项目使用了以下库:
* [xunit](https://xunit.github.io/) 作为主测试框架. * [xunit](https://xunit.github.io/) 作为主测试框架.
* [Shoudly](http://shouldly.readthedocs.io/en/latest/) 作为断言库. * [Shoudly](http://shouldly.readthedocs.io/en/latest/) 作为断言库.
@ -26,79 +24,39 @@
### 添加测试用数据 ### 添加测试用数据
起始模板在 `Acme.BookStore.Application.Tests` 项目中包含了 `BookStoreTestDataBuilder` 类,用于创建一些测试用数据. 相关代码如下所示: 启动模板包含`Acme.BookStore.TestBase`项目中的`BookStoreTestDataSeedContributor`类,它创建一些数据来运行测试.
更改`BookStoreTestDataSeedContributor`类如下所示:
````C#
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.Threading;
namespace Acme.BookStore
{
public class BookStoreTestDataBuilder : ITransientDependency
{
private readonly IIdentityDataSeeder _identityDataSeeder;
public BookStoreTestDataBuilder(IIdentityDataSeeder identityDataSeeder)
{
_identityDataSeeder = identityDataSeeder;
}
public void Build()
{
AsyncHelper.RunSync(BuildInternalAsync);
}
public async Task BuildInternalAsync()
{
await _identityDataSeeder.SeedAsync("1q2w3E*");
}
}
}
````
* 这里直接使用了identity模块实现的 `IIdentityDataSeeder` 接口,创建了一个admin角色和admin用户.你可以在测试代码中使用它们.
* 你可以在 `BuildInternalAsync` 方法中添加你自己的测试数据.
按下方所示修改 `BookStoreTestDataBuilder` 类:
````C# ````C#
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity; using Volo.Abp.Guids;
using Volo.Abp.Threading;
namespace Acme.BookStore namespace Acme.BookStore
{ {
public class BookStoreTestDataBuilder : ITransientDependency public class BookStoreTestDataSeedContributor
: IDataSeedContributor, ITransientDependency
{ {
private readonly IIdentityDataSeeder _identityDataSeeder;
private readonly IRepository<Book, Guid> _bookRepository; private readonly IRepository<Book, Guid> _bookRepository;
private readonly IGuidGenerator _guidGenerator;
public BookStoreTestDataBuilder( public BookStoreTestDataSeedContributor(
IIdentityDataSeeder identityDataSeeder, IRepository<Book, Guid> bookRepository,
IRepository<Book, Guid> bookRepository) IGuidGenerator guidGenerator)
{ {
_identityDataSeeder = identityDataSeeder;
_bookRepository = bookRepository; _bookRepository = bookRepository;
_guidGenerator = guidGenerator;
} }
public void Build() public async Task SeedAsync(DataSeedContext context)
{ {
AsyncHelper.RunSync(BuildInternalAsync);
}
public async Task BuildInternalAsync()
{
await _identityDataSeeder.SeedAsync("1q2w3E*");
await _bookRepository.InsertAsync( await _bookRepository.InsertAsync(
new Book new Book
{ {
Id = Guid.NewGuid(), Id = _guidGenerator.Create(),
Name = "Test book 1", Name = "Test book 1",
Type = BookType.Fantastic, Type = BookType.Fantastic,
PublishDate = new DateTime(2015, 05, 24), PublishDate = new DateTime(2015, 05, 24),
@ -109,7 +67,7 @@ namespace Acme.BookStore
await _bookRepository.InsertAsync( await _bookRepository.InsertAsync(
new Book new Book
{ {
Id = Guid.NewGuid(), Id = _guidGenerator.Create(),
Name = "Test book 2", Name = "Test book 2",
Type = BookType.Science, Type = BookType.Science,
PublishDate = new DateTime(2014, 02, 11), PublishDate = new DateTime(2014, 02, 11),
@ -121,7 +79,8 @@ namespace Acme.BookStore
} }
```` ````
* 通过构造函数注入 `IRepository<Book, Guid>`,在 `BuildInternalAsync` 方法中用它创建两个book实体. * 注入`IRepository<Book,Guid>`并在`SeedAsync`中使用它来创建两个书实体作为测试数据.
* 使用`IGuidGenerator`服务创建GUID. 虽然`Guid.NewGuid()`非常适合测试,但`IGuidGenerator`在使用真实数据库时还有其他特别重要的功能(参见[Guid生成文档](../../Guid-Generation.md)了解更多信息).
### 测试 BookAppService ### 测试 BookAppService
@ -211,6 +170,8 @@ public async Task Should_Not_Create_A_Book_Without_Name()
* 由于 `Name` 是空值, ABP 抛出一个 `AbpValidationException` 异常. * 由于 `Name` 是空值, ABP 抛出一个 `AbpValidationException` 异常.
### 测试 Web 页面 打开**测试资源管理器**(测试 -> Windows -> 测试资源管理器)并**执行**所有测试:
![bookstore-appservice-tests](images/bookstore-appservice-tests.png)
TODO 恭喜, 绿色图标表示测试已成功通过!

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-appservice-tests.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-test-projects-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-test-projects.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

3
docs/zh-Hans/Value-Objects.md

@ -0,0 +1,3 @@
## Value Objects
TODO

4
docs/zh-Hans/docs-nav.json

@ -41,6 +41,10 @@
} }
] ]
}, },
{
"text": "CLI",
"path": "CLI.md"
},
{ {
"text": "基础知识", "text": "基础知识",
"items": [ "items": [

BIN
docs/zh-Hans/images/bookstore-user-management-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/zh-Hans/images/bookstore-user-management.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/zh-Hans/images/bookstore-visual-studio-solution-tiered.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/zh-Hans/images/bookstore-visual-studio-solution-v2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

BIN
docs/zh-Hans/images/bookstore-visual-studio-solution-v3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/zh-Hans/images/bookstore-visual-studio-solution.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

BIN
docs/zh-Hans/images/db-migrator-app.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/zh-Hans/images/disable-package-restore-visual-studio.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

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

Loading…
Cancel
Save