From 37615d7de62c4b0546e8654f6ae2ec42a7c1af53 Mon Sep 17 00:00:00 2001 From: Hamza Albreem <94292623+braim23@users.noreply.github.com> Date: Thu, 30 Dec 2021 11:33:46 +0300 Subject: [PATCH 01/18] Editing the Quick Start Docs --- docs/en/Tutorials/Todo/Index.md | 74 ++++++++++++++++----------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/docs/en/Tutorials/Todo/Index.md b/docs/en/Tutorials/Todo/Index.md index ea2551d4f5..7b232c4873 100644 --- a/docs/en/Tutorials/Todo/Index.md +++ b/docs/en/Tutorials/Todo/Index.md @@ -8,11 +8,11 @@ } ```` -This is a single-part, quick-start tutorial to build a simple todo application with the ABP Framework. Here, a screenshot from the final application: +This is a single-part quick-start tutorial to build a simple todo application with the ABP Framework. Here's a screenshot from the final application: ![todo-list](todo-list.png) -You can find source code of the completed application [here](https://github.com/abpframework/abp-samples/tree/master/TodoApp). +You can find the source code of the completed application [here](https://github.com/abpframework/abp-samples/tree/master/TodoApp). ## Pre-Requirements @@ -56,7 +56,7 @@ This will create a new solution, named *TodoApp*. Once the solution is ready, op ### Create the Database -If you are using Visual Studio, right click to the `TodoApp.DbMigrator` project, select *Set as StartUp Project*, then hit *Ctrl+F5* to run it without debugging. It will create the initial database and seed the initial data. +If you are using Visual Studio, right click on the `TodoApp.DbMigrator` project, select *Set as StartUp Project*, then hit *Ctrl+F5* to run it without debugging. It will create the initial database and seed the initial data. {{if DB=="EF"}} @@ -74,7 +74,7 @@ It is good to run the application before starting the development. Ensure the {{ It is good to run the application before starting the development. The solution has two main applications; -* `TodoApp.HttpApi.Host` host the server-side HTTP API. +* `TodoApp.HttpApi.Host` hosts the server-side HTTP API. * `TodoApp.Blazor` is the client-side Blazor WebAssembly application. Ensure the `TodoApp.HttpApi.Host` project is the startup project, then run the application (Ctrl+F5 in Visual Studio) to see the server-side HTTP API on the [Swagger UI](https://swagger.io/tools/swagger-ui/): @@ -85,16 +85,16 @@ You can explore and test your HTTP API with this UI. Now, we can set the `TodoAp {{else if UI=="NG"}} -It is good to run the application before starting the development. The solution has two main applications; +It is good to run the application before starting the development. The solution has two main applications: * `TodoApp.HttpApi.Host` (in the .NET solution) host the server-side HTTP API. * `angular` folder contains the Angular application. -Ensure the `TodoApp.HttpApi.Host` project is the startup project, then run the application (Ctrl+F5 in Visual Studio) to see the server-side HTTP API on the [Swagger UI](https://swagger.io/tools/swagger-ui/): +Ensure that the `TodoApp.HttpApi.Host` project is the startup project, then run the application (Ctrl+F5 in Visual Studio) to see the server-side HTTP API on the [Swagger UI](https://swagger.io/tools/swagger-ui/): ![todo-swagger-ui-initial](todo-swagger-ui-initial.png) -You can explore and test your HTTP API with this UI. If that works, we can run the Angular client application. +You can explore and test your HTTP API with this UI. If it works, we can run the Angular client application. First, run the following command to restore the NPM packages; @@ -114,13 +114,13 @@ This command takes time, but eventually runs and opens the application in your d ![todo-ui-initial](todo-ui-initial.png) -You can click to the *Login* button, use `admin` as the username and `1q2w3E*` as the password to login to the application. +You can click on the *Login* button, use `admin` as the username and `1q2w3E*` as the password to login to the application. -All ready. We can start the coding! +All ready. We can start coding! ## Domain Layer -This application has a single [entity](../../Entities.md) and we are starting by creating it. Create a new `TodoItem` class inside the *TodoApp.Domain* project: +This application has a single [entity](../../Entities.md) and we'll start by creating it. Create a new `TodoItem` class inside the *TodoApp.Domain* project: ````csharp using System; @@ -151,7 +151,7 @@ Open the `TodoAppDbContext` class in the `EntityFrameworkCore` folder of the *To public DbSet TodoItems { get; set; } ```` -Then locate to `OnModelCreating` method in the `TodoAppDbContext` class and add the mapping code for the `TodoItem ` entity: +Then navigate to the `OnModelCreating` method in the `TodoAppDbContext` class and add the mapping code for the `TodoItem ` entity: ````csharp protected override void OnModelCreating(ModelBuilder builder) @@ -171,7 +171,7 @@ protected override void OnModelCreating(ModelBuilder builder) } ```` -We've mapped `TodoItem` entity to a `TodoItems` table in the database. +We've mapped the `TodoItem` entity to the `TodoItems` table in the database. ### Code First Migrations @@ -193,11 +193,11 @@ You can apply changes to the database using the following command, in the same c dotnet ef database update ```` -> If you are using Visual Studio, you may want to use `Add-Migration Added_TodoItem` and `Update-Database` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`TodoApp.Web`{{else if UI=="BlazorServer"}}`TodoApp.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`TodoApp.HttpApi.Host`{{end}} is the startup project and `TodoApp.EntityFrameworkCore` is the *Default Project* in PMC. +> If you are using Visual Studio, you may want to use the `Add-Migration Added_TodoItem` and `Update-Database` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`TodoApp.Web`{{else if UI=="BlazorServer"}}`TodoApp.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`TodoApp.HttpApi.Host`{{end}} is the startup project and `TodoApp.EntityFrameworkCore` is the *Default Project* in PMC. {{else if DB=="Mongo"}} -Next step is to setup the [MongoDB](../../MongoDB.md) configuration. Open the `TodoAppMongoDbContext` class in the `MongoDb` folder of the *TodoApp.MongoDB* project and make the following changes; +Next step is to setup the [MongoDB](../../MongoDB.md) configuration. Open the `TodoAppMongoDbContext` class in the `MongoDb` folder of the *TodoApp.MongoDB* project and make the following changes: 1. Add a new property to the class: @@ -216,13 +216,13 @@ modelBuilder.Entity(b => {{end}} -Now, we can use ABP repositories to save and retrieve todo items, as we'll do in the next section. +Now, we can use the ABP repositories to save and retrieve the todo items, as we'll do in the next section. ## Application Layer -An [Application Service](../../Application-Services.md) is used to perform use cases of the application. We need to perform the following use cases: +An [Application Service](../../Application-Services.md) is used to perform the use cases of the application. We need to perform the following use cases: -* Get the list of todo items +* Get the list of the todo items * Create a new todo item * Delete an existing todo item @@ -264,7 +264,7 @@ namespace TodoApp } ```` -This is a very simple DTO class that matches to our `TodoItem` entity. We are ready to implement the `ITodoAppService`. +This is a very simple DTO class that matches our `TodoItem` entity. We are ready to implement the `ITodoAppService`. ### Application Service Implementation @@ -313,7 +313,7 @@ public async Task> GetListAsync() } ```` -We are simply getting the complete `TodoItem` list from database, mapping them to `TodoItemDto` objects and returning as the result. +We are simply getting the complete `TodoItem` list from the database, mapping them to `TodoItemDto` objects and returning as the result. #### Creating a New Todo Item @@ -334,7 +334,7 @@ public async Task CreateAsync(string text) } ```` -Repository's `InsertAsync` method inserts the given `TodoItem` to database and returns the same `TodoItem` object. It also sets the `Id`, so we can use it on the returning object. We are simply returning a `TodoItemDto` by creating from the new `TodoItem` entity. +The repository's `InsertAsync` method inserts the given `TodoItem` to the database and returns the same `TodoItem` object. It also sets the `Id`, so we can use it on the returning object. We are simply returning a `TodoItemDto` by creating from the new `TodoItem` entity. #### Deleting a Todo Item @@ -351,7 +351,7 @@ The application service is ready to be used from the UI layer. ## User Interface Layer -It is time to show the todo items on the UI! Before starting to write the code, it would be good to remember what we are trying to build. Here, a sample screenshot from the final UI: +It is time to show the todo items on the UI! Before starting to write the code, it would be good to remember what we are trying to build. Here's a sample screenshot from the final UI: ![todo-list](todo-list.png) @@ -388,11 +388,11 @@ namespace TodoApp.Web.Pages } ```` -This class uses the `ITodoAppService` to get the list of todo items and assign the the `TodoItems` property. We will use it to render the todo items on the razor page. +This class uses the `ITodoAppService` to get the list of todo items and assign the `TodoItems` property. We will use it to render the todo items on the razor page. ### Index.cshtml -Open the `Index.cshtml` file in the `Pages` folder of the *TodoApp.Web* project and replace with the following content: +Open the `Index.cshtml` file in the `Pages` folder of the *TodoApp.Web* project and replace it with the following content: ````xml @page @@ -442,7 +442,7 @@ This page imports a CSS and a JavaScript file, so we should also create them. ### Index.js -Open the `Index.js` file in the `Pages` folder of the *TodoApp.Web* project and replace with the following content: +Open the `Index.js` file in the `Pages` folder of the *TodoApp.Web* project and replace it with the following content: ````js $(function () { @@ -473,15 +473,15 @@ $(function () { }); ```` -In the first part, we are subscribing to click events of the trash icons near to the todo items, deleting the related item on the server and showing a notification on the UI. Also, we are removing the deleted item from DOM, so we don't need to refresh the page. +In the first part, we are subscribing to the click events of the trash icons near the todo items, deleting the related item on the server and showing a notification on the UI. Also, we are removing the deleted item from the DOM, so we don't need to refresh the page. -In the second part, we are creating a new todo item on the server. If it succeeds, we are then manipulating DOM to insert a new `
  • ` element to the todo list. This way we don't need to refresh the whole page after creating a new todo item. +In the second part, we are creating a new todo item on the server. If it succeeds, we are then manipulating the DOM to insert a new `
  • ` element to the todo list. This way we don't need to refresh the whole page after creating a new todo item. The interesting part here is how we communicate with the server. See the *Dynamic JavaScript Proxies & Auto API Controllers* section to understand how it works. But now, let's continue and complete the application. ### Index.css -As the final touch, open the `Index.css` file in the `Pages` folder of the *TodoApp.Web* project and replace with the following content: +As the final touch, open the `Index.css` file in the `Pages` folder of the *TodoApp.Web* project and replace it with the following content: ````css #TodoList{ @@ -516,9 +516,9 @@ Now, you can run the application again and see the result. ### Dynamic JavaScript Proxies & Auto API Controllers -In the `Index.js` file, we've used `todoApp.todo.delete(...)` and `todoApp.todo.create(...)` functions to communicate with the server. These functions are dynamically created by the ABP Framework, thanks to the [Dynamic JavaScript Client Proxy](../../UI/AspNetCore/Dynamic-JavaScript-Proxies.md) system. They perform HTTP API calls to the server and return a promise, so you can register a callback to the `then` function as we've done above. +In the `Index.js` file, we've used the `todoApp.todo.delete(...)` and `todoApp.todo.create(...)` functions to communicate with the server. These functions are dynamically created by the ABP Framework, thanks to the [Dynamic JavaScript Client Proxy](../../UI/AspNetCore/Dynamic-JavaScript-Proxies.md) system. They perform HTTP API calls to the server and return a promise, so you can register a callback to the `then` function as we've done above. -However, you may notice that we haven't created any API Controller, so how server handles these requests? This question brings us the [Auto API Controller](../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to API Controllers by convention. +However, you may notice that we haven't created any API Controllers, so how does the server handle these requests? This question brings us to the [Auto API Controller](../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to API Controllers by convention. If you open the [Swagger UI](https://swagger.io/tools/swagger-ui/) by entering the `/swagger` URL in your application, you can see the Todo API: @@ -567,7 +567,7 @@ namespace TodoApp.Blazor.Pages } ```` -This class uses the `ITodoAppService` to perform operations for the todo items. It manipulates the `TodoItems` list after create and delete operations. This way, we don't need to refresh the whole todo list from the server. +This class uses `ITodoAppService` to perform operations for the todo items. It manipulates the `TodoItems` list after create and delete operations. This way, we don't need to refresh the whole todo list from the server. {{if UI=="Blazor"}} @@ -619,7 +619,7 @@ Open the `Index.razor` file in the `Pages` folder of the *TodoApp.Blazor* projec ### Index.razor.css -As the final touch, open the `Index.razor.css` file in the `Pages` folder of the *TodoApp.Blazor* project and replace with the following content: +As the final touch, open the `Index.razor.css` file in the `Pages` folder of the *TodoApp.Blazor* project and replace it with the following content: ````css #TodoList{ @@ -660,7 +660,7 @@ In the `Index.razor.cs` file, we've injected (with the `[Inject]` attribute) and The magic is done by the ABP Framework's [Dynamic C# Client Proxy](../../API/Dynamic-CSharp-API-Clients.md) system. It uses the standard `HttpClient` and performs HTTP API requests to the remote server. It also handles all the standard tasks for us, including authorization, JSON serialization and exception handling. -However, you may ask that we haven't created any API Controller, so how server handles these requests? This question brings us the [Auto API Controller](../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to API Controllers by convention. +However, you may ask that we haven't created any API Controller, so how does the server handle these requests? This question brings us to the [Auto API Controller](../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to API Controllers by convention. If you run the `TodoApp.HttpApi.Host` application, you can see the Todo API: @@ -676,7 +676,7 @@ ABP provides a handy feature to automatically create client-side services to eas You first need to run the `TodoApp.HttpApi.Host` project since the proxy generator reads API definitions from the server application. -> **Warning**: There is an issue with IIS Express: it doesn't allow to connect to the application from another process. If you are using Visual Studio, select the `TodoApp.HttpApi.Host` instead of IIS Express in the run button drop-down list, as shown in the figure below: +> **Warning**: There is an issue with IIS Express: it doesn't allow connecting to the application from another process. If you are using Visual Studio, select the `TodoApp.HttpApi.Host` instead of IIS Express in the run button drop-down list, as shown in the figure below: ![run-without-iisexpress](run-without-iisexpress.png) @@ -686,7 +686,7 @@ Once you run the `TodoApp.HttpApi.Host` project, open a command-line terminal in abp generate-proxy -t ng ```` -If everything goes well, it should generate an output like shown below: +If everything goes well, it should generate an output as shown below: ````bash CREATE src/app/proxy/generate-proxy.json (170978 bytes) @@ -696,7 +696,7 @@ CREATE src/app/proxy/models.ts (66 bytes) CREATE src/app/proxy/index.ts (58 bytes) ```` -We can then use the `todoService` to use the server-side HTTP APIs, as we'll do in the next section. +We can then use `todoService` to use the server-side HTTP APIs, as we'll do in the next section. ### home.component.ts @@ -745,7 +745,7 @@ export class HomeComponent implements OnInit { ```` -We've used the `todoService` to get the list of todo items and assigned the returning value to the `todoItems` array. We've also added `create` and `delete` methods. These methods will be used in the view side. +We've used `todoService` to get the list of todo items and assigned the returning value to the `todoItems` array. We've also added `create` and `delete` methods. These methods will be used on the view side. ### home.component.html @@ -819,7 +819,7 @@ Now, you can run the application again to see the result. ## Conclusion -In this tutorial, we've built a very simple application to warm up to the ABP Framework. If you are looking to build a serious application, please check the [web application development tutorial](../Part-1.md) which covers all the aspects of a real-life web application development. +In this tutorial, we've built a very simple application to warm up for the ABP Framework. If you are looking to build a serious application, please check the [web application development tutorial](../Part-1.md) which covers all the aspects of real-life web application development. ## Source Code From bb4ee2a67235379f534313118a553e1e3ef33dbc Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 31 Dec 2021 10:47:18 +0800 Subject: [PATCH 02/18] Update codecov.yml --- codecov.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/codecov.yml b/codecov.yml index 7ad4672daf..a2bd04f1d8 100644 --- a/codecov.yml +++ b/codecov.yml @@ -2,3 +2,7 @@ codecov: branch: dev require_ci_to_pass: yes allow_coverage_offsets: true + status: + project: + default: + threshold: 1% From 3b9fcc77cdde390840fbd8113c001dbbed7f504f Mon Sep 17 00:00:00 2001 From: braim23 <94292623+braim23@users.noreply.github.com> Date: Sat, 1 Jan 2022 20:18:26 +0300 Subject: [PATCH 03/18] Update Part-1.md --- docs/en/Tutorials/Part-1.md | 45 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/docs/en/Tutorials/Part-1.md b/docs/en/Tutorials/Part-1.md index 210ecbe966..93bf3d4a0b 100644 --- a/docs/en/Tutorials/Part-1.md +++ b/docs/en/Tutorials/Part-1.md @@ -13,7 +13,7 @@ In this tutorial series, you will build an ABP based web application named `Acme * **{{DB_Value}}** as the database provider. * **{{UI_Value}}** as the UI Framework. -This tutorial is organized as the following parts; +This tutorial is organized as the following parts: - **Part 1: Creating the server side (this part)** - [Part 2: The book list page](Part-2.md) @@ -34,7 +34,7 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) -> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later). +> If you encounter the "filename too long" or "unzip" error on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later). > If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path > `git config --system core.longpaths true` @@ -49,14 +49,14 @@ This part is also recorded as a video tutorial and ** @@ -147,7 +147,7 @@ public class BookStoreMongoDbContext : AbpMongoDbContext ### Map the Book Entity to a Database Table -Locate to `OnModelCreating` method in the `BookStoreDbContext` class and add the mapping code for the `Book` entity: +Navigate to the `OnModelCreating` method in the `BookStoreDbContext` class and add the mapping code for the `Book` entity: ````csharp using Acme.BookStore.Books; @@ -185,8 +185,8 @@ namespace Acme.BookStore.EntityFrameworkCore } ```` -* `BookStoreConsts` has constant values for schema and table prefixes for your tables. You don't have to use it, but suggested to control the table prefixes in a single point. -* `ConfigureByConvention()` method gracefully configures/maps the inherited properties. Always use it for all your entities. +* `BookStoreConsts` has constant values for the schema and table prefixes for your tables. You don't have to use it, but it's suggested to control the table prefixes in a single point. +* The `ConfigureByConvention()` method gracefully configures/maps the inherited properties. Always use it for all your entities. ### Add Database Migration @@ -202,13 +202,13 @@ This will add a new migration class to the project: ![bookstore-efcore-migration](./images/bookstore-efcore-migration.png) -> If you are using Visual Studio, you may want to use `Add-Migration Created_Book_Entity -c BookStoreMigrationsDbContext` and `Update-Database -c BookStoreMigrationsDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. +> If you are using Visual Studio, you may want to use the `Add-Migration Created_Book_Entity -c BookStoreMigrationsDbContext` and `Update-Database -c BookStoreMigrationsDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. {{end}} ### Add Sample Seed Data -> It's good to have some initial data in the database before running the application. This section introduces the [Data Seeding](../Data-Seeding.md) system of the ABP framework. You can skip this section if you don't want to create seed data, but it is suggested to follow it to learn this useful ABP Framework feature. +> It's good to have some initial data in the database before running the application. This section introduces the [Data Seeding](../Data-Seeding.md) system of the ABP framework. You can skip this section if you don't want to create the data seeding, but it is suggested to follow along and learn this useful ABP Framework feature. Create a class deriving from the `IDataSeedContributor` in the `*.Domain` project by copying the following code: @@ -263,7 +263,7 @@ namespace Acme.BookStore } ``` -* This code simply uses the `IRepository` (the default [repository](../Repositories.md)) to insert two books to the database, if there is no book currently in the database. +* This code simply uses the `IRepository` (the default [repository](../Repositories.md)) to insert two books to the database in case there weren't any books in it. ### Update the Database @@ -271,7 +271,6 @@ Run the `Acme.BookStore.DbMigrator` application to update the database: ![bookstore-dbmigrator-on-solution](images/bookstore-dbmigrator-on-solution.png) - `.DbMigrator` is a console application that can be run to **migrate the database schema** and **seed the data** on **development** and **production** environments. ## Create the Application Service @@ -307,10 +306,10 @@ namespace Acme.BookStore.Books ```` * **DTO** classes are used to **transfer data** between the *presentation layer* and the *application layer*. See the [Data Transfer Objects document](https://docs.abp.io/en/abp/latest/Data-Transfer-Objects) 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 derived from the `AuditedEntityDto` which has audit properties just like the `Book` entity defined above. +* The `BookDto` is used to transfer the book data to the presentation layer in order to show the book information on the UI. +* The `BookDto` is derived from the `AuditedEntityDto` which has audit properties just like the `Book` entity defined above. -It will be needed to map `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. The startup template comes with AutoMapper pre-configured. So, you can just define the mapping in the `BookStoreApplicationAutoMapperProfile` class in the `Acme.BookStore.Application` project: +It will be needed to map the `Book` entities to the `BookDto` objects while returning books to the presentation layer. [AutoMapper](https://automapper.org) library can automate this conversion when you define the proper mapping. The startup template comes with AutoMapper pre-configured. So, you can just define the mapping in the `BookStoreApplicationAutoMapperProfile` class in the `Acme.BookStore.Application` project: ````csharp using Acme.BookStore.Books; @@ -359,10 +358,10 @@ namespace Acme.BookStore.Books } ```` -* 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 a book information from the user interface while creating or updating the book. * It defines data annotation attributes (like `[Required]`) to define validations for the properties. `DTO`s are [automatically validated](https://docs.abp.io/en/abp/latest/Validation) by the ABP framework. -Just like done for the `BookDto` above, we should define the mapping from the `CreateUpdateBookDto` object to the `Book` entity. The final class will be like shown below: +As done to the `BookDto` above, we should define the mapping from the `CreateUpdateBookDto` object to the `Book` entity. The final class will be as shown below: ````csharp using Acme.BookStore.Books; @@ -440,13 +439,13 @@ namespace Acme.BookStore.Books * `BookAppService` is derived from `CrudAppService<...>` which implements all the CRUD (create, read, update, delete) methods defined by the `ICrudAppService`. * `BookAppService` injects `IRepository` which is the default repository for the `Book` entity. ABP automatically creates default repositories for each aggregate root (or entity). See the [repository document](https://docs.abp.io/en/abp/latest/Repositories). -* `BookAppService` uses `IObjectMapper` service ([see](../Object-To-Object-Mapping.md)) to map `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. We have defined the mappings before, so it will work as expected. +* `BookAppService` uses `IObjectMapper` service ([see](../Object-To-Object-Mapping.md)) to map the `Book` objects to the `BookDto` objects and `CreateUpdateBookDto` objects to the `Book` objects. The Startup template uses the [AutoMapper](http://automapper.org/) library as the object mapping provider. We have defined the mappings before, so it will work as expected. ## Auto API Controllers -In a typical ASP.NET Core application, you create **API Controllers** to expose application services as **HTTP API** endpoints. This allows browsers or 3rd-party clients to call them over HTTP. +In a typical ASP.NET Core application, you create **API Controllers** to expose the application services as **HTTP API** endpoints. This allows browsers or 3rd-party clients to call them over HTTP. -ABP can [**automagically**](../API/Auto-API-Controllers.md) configures your application services as MVC API Controllers by convention. +ABP can [**automagically**](../API/Auto-API-Controllers.md) configure your application services as MVC API Controllers by convention. ### Swagger UI From dceb36b1d9d9969368035e19ebde3dce31dfbe1a Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 3 Jan 2022 13:30:05 +0300 Subject: [PATCH 04/18] Improve studio --- .../Abp/Studio/Modifying/CsprojFileManager.cs | 40 +++++++++++++++++++ .../Studio/Modifying/ICsprojFileManager.cs | 4 ++ .../ModuleInstallingPipelineBuilderBase.cs | 2 +- .../Steps/AddEfCoreConfigurationMethodStep.cs | 9 ++++- ...monPropsStep.cs => AssemblyVersionStep.cs} | 5 ++- 5 files changed, 56 insertions(+), 4 deletions(-) rename studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/{CommonPropsStep.cs => AssemblyVersionStep.cs} (77%) diff --git a/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/CsprojFileManager.cs b/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/CsprojFileManager.cs index c37321decf..a9f4227c34 100644 --- a/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/CsprojFileManager.cs +++ b/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/CsprojFileManager.cs @@ -92,6 +92,46 @@ public class CsprojFileManager : XmlFileManagerBase, ICsprojFileManager, ITransi await SaveXmlDocumentAsync(filePath, document); } + public async Task AddAssemblyVersionAsync(string filePath, string version) + { + var document = await GetXmlDocumentAsync(filePath); + + var matchedNodes = document.SelectNodes($"/Project/PropertyGroup"); + + if (matchedNodes.Count == 0) + { + return; + } + + var versionNode = document.CreateElement("Version"); + + versionNode.InnerText = version; + + matchedNodes[0].AppendChild(versionNode); + + await SaveXmlDocumentAsync(filePath, document); + } + + public async Task AddCopyLocalLockFileAssembliesAsync(string filePath) + { + var document = await GetXmlDocumentAsync(filePath); + + var matchedNodes = document.SelectNodes($"/Project/PropertyGroup"); + + if (matchedNodes.Count == 0) + { + return; + } + + var versionNode = document.CreateElement("CopyLocalLockFileAssemblies"); + + versionNode.InnerText = "True"; + + matchedNodes[0].AppendChild(versionNode); + + await SaveXmlDocumentAsync(filePath, document); + } + public async Task ConvertPackageReferenceToProjectReferenceAsync(string filePath, string projectToReference) { var document = await GetXmlDocumentAsync(filePath); diff --git a/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/ICsprojFileManager.cs b/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/ICsprojFileManager.cs index 287debad65..b0617f10f7 100644 --- a/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/ICsprojFileManager.cs +++ b/studio/src/Volo.Abp.Studio.Domain.CommonServices/Volo/Abp/Studio/Modifying/ICsprojFileManager.cs @@ -12,6 +12,10 @@ public interface ICsprojFileManager Task AddImportAsync(string filePath, string importFilePath); + Task AddAssemblyVersionAsync(string filePath, string version); + + Task AddCopyLocalLockFileAssembliesAsync(string filePath); + Task ConvertPackageReferenceToProjectReferenceAsync(string filePath, string projectToReference); diff --git a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/ModuleInstallingPipelineBuilderBase.cs b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/ModuleInstallingPipelineBuilderBase.cs index 5b3f953e1a..4c061ae87d 100644 --- a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/ModuleInstallingPipelineBuilderBase.cs +++ b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/ModuleInstallingPipelineBuilderBase.cs @@ -12,7 +12,7 @@ public abstract class ModuleInstallingPipelineBuilderBase if (context.WithSourceCode) { pipeline.Add(new SourceCodeDownloadStep()); - pipeline.Add(new CommonPropsStep()); + pipeline.Add(new AssemblyVersionStep()); if (context.AddToSolutionFile) { diff --git a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AddEfCoreConfigurationMethodStep.cs b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AddEfCoreConfigurationMethodStep.cs index 05e0d2073c..20caa109ba 100644 --- a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AddEfCoreConfigurationMethodStep.cs +++ b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AddEfCoreConfigurationMethodStep.cs @@ -36,7 +36,14 @@ public class AddEfCoreConfigurationMethodStep : ModuleInstallingPipelineStep foreach (var declaration in context.EfCoreConfigurationMethodDeclarations) { - _dbContextFileBuilderConfigureAdder.Add(dbContextFile, declaration.Namespace + ":" + declaration.MethodName); + try + { + _dbContextFileBuilderConfigureAdder.Add(dbContextFile, declaration.Namespace + ":" + declaration.MethodName); + } + catch (Exception e) + { + continue; + } } } } diff --git a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/CommonPropsStep.cs b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AssemblyVersionStep.cs similarity index 77% rename from studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/CommonPropsStep.cs rename to studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AssemblyVersionStep.cs index 519cc31c06..ecd83db1b1 100644 --- a/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/CommonPropsStep.cs +++ b/studio/src/Volo.Abp.Studio.ModuleInstaller/Volo/Abp/Studio/ModuleInstalling/Steps/AssemblyVersionStep.cs @@ -5,7 +5,7 @@ using Volo.Abp.Studio.Packages.Modifying; namespace Volo.Abp.Studio.ModuleInstalling.Steps; -public class CommonPropsStep : ModuleInstallingPipelineStep +public class AssemblyVersionStep : ModuleInstallingPipelineStep { public async override Task ExecuteAsync(ModuleInstallingContext context) { @@ -23,7 +23,8 @@ public class CommonPropsStep : ModuleInstallingPipelineStep foreach (var csProjFile in csProjFiles) { - await _csprojFileManager.AddImportAsync(csProjFile, commonPropsFilePath); + await _csprojFileManager.AddAssemblyVersionAsync(csProjFile, context.Version); + await _csprojFileManager.AddCopyLocalLockFileAssembliesAsync(csProjFile); } } } From a281d5b07e6d1f69e7adedc3e0cf7d9b8a52d8a8 Mon Sep 17 00:00:00 2001 From: enisn Date: Mon, 3 Jan 2022 14:22:09 +0300 Subject: [PATCH 05/18] Add distributed cache prerequirement section to CMS Kit documentation --- docs/en/Modules/Cms-Kit/Index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index 4c422b0bf3..e57bc3519a 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -18,6 +18,12 @@ Click to a feature to understand and learn how to use it. All features are individually usable. If you disable a feature, it completely disappears from your application, even from the database tables, by the help of the [Global Features](../../Global-Features.md) system. +## Pre Requirements + +CMS Kit uses [distributed cache](../../Caching.md) for responding faster. + +> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommented for data consistency. + ## How to Install > This module is depends on [BlobStoring](../../Blob-Storing.md) module, please install `BlobStoring` module first and add a provider. For more information, check the [documentation](../../Blob-Storing.md). From b51a9f21bc5c813d12678da0ad288cc61672a7dd Mon Sep 17 00:00:00 2001 From: enisn Date: Mon, 3 Jan 2022 14:24:09 +0300 Subject: [PATCH 06/18] Typo fix at CMS-Kit documentation --- docs/en/Modules/Cms-Kit/Index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index e57bc3519a..cb2e341d16 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -22,7 +22,7 @@ All features are individually usable. If you disable a feature, it completely di CMS Kit uses [distributed cache](../../Caching.md) for responding faster. -> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommented for data consistency. +> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommended for data consistency. ## How to Install From e0e67a66dca04dd6550f6888cb4f187451fb49f5 Mon Sep 17 00:00:00 2001 From: enisn Date: Mon, 3 Jan 2022 14:26:53 +0300 Subject: [PATCH 07/18] Update Index.md --- docs/en/Modules/Cms-Kit/Index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index cb2e341d16..fc28736a70 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -22,7 +22,7 @@ All features are individually usable. If you disable a feature, it completely di CMS Kit uses [distributed cache](../../Caching.md) for responding faster. -> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommended for data consistency. +> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommended for data consistency in tiered solutions. ## How to Install From f37988b1370477516dfcaa75737f54a5d7c773cc Mon Sep 17 00:00:00 2001 From: albert <9526587+ebicoglu@users.noreply.github.com> Date: Mon, 3 Jan 2022 17:07:07 +0300 Subject: [PATCH 08/18] Clearify HowManyProductsExplanation --- .../AbpIoLocalization/Commercial/Localization/Resources/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index 6224c74049..d99821912d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -172,7 +172,7 @@ "StartDevelopWithTutorials": "The downloaded solution is well architected and documented. You can start to develop your own business code based on it following the tutorials", "TryTheCommercialDemo": "You can try the demo to see a sample application created using the ABP Commercial startup template.", "HowManyProducts": "How many different products/solutions can I build using the ABP Commercial?", - "HowManyProductsExplanation": "There is no limit to create an ABP project. You can create as many project as you want, develop and upload them to different servers.", + "HowManyProductsExplanation": "You can create as many projects as you want during your active license period, there is no limit! After your license expires, you cannot create new projects, but you can continue to develop the projects you have downloaded and deploy them to an unlimited count of servers.", "HowManyDevelopers": "How many developers can work on the ABP Commercial?", "HowManyDevelopersExplanation": "ABP Commercial licenses are per developer. Different license types have different developer limits. However, you can add more developers to any license type whenever you need. See the prices page for license types, developer limits and additional developer costs.", "ChangingLicenseType": "Can I upgrade my license type later?", From 6e93d155ffcdeb7871d402b5b717588623ecdba5 Mon Sep 17 00:00:00 2001 From: braim23 <94292623+braim23@users.noreply.github.com> Date: Mon, 3 Jan 2022 17:42:28 +0300 Subject: [PATCH 09/18] Update Part-2.md --- docs/en/Tutorials/Part-2.md | 86 ++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/en/Tutorials/Part-2.md b/docs/en/Tutorials/Part-2.md index 4b29231164..6d636d5ecb 100644 --- a/docs/en/Tutorials/Part-2.md +++ b/docs/en/Tutorials/Part-2.md @@ -13,7 +13,7 @@ In this tutorial series, you will build an ABP based web application named `Acme * **{{DB_Value}}** as the ORM provider. * **{{UI_Value}}** as the UI Framework. -This tutorial is organized as the following parts; +This tutorial is organized as the following parts: - [Part 1: Creating the server side](Part-1.md) - **Part 2: The book list page (this part)** @@ -53,7 +53,7 @@ This part is also recorded as a video tutorial and ** Razor Page** menu item. Name it as `Index`: +Create a `Books` folder under the `Pages` folder of the `Acme.BookStore.Web` project. Add a new Razor Page by right clicking the Books folder then selecting **Add > Razor Page** menu item. Name it as `Index`: ![bookstore-add-index-page](images/bookstore-add-index-page-v2.png) @@ -213,21 +213,21 @@ context.Menu.AddItem( ); ```` -Run the project, login to the application with the username `admin` and the password `1q2w3E*` and see the new menu item has been added to the main menu: +Run the project, login to the application with the username `admin` and the password `1q2w3E*` and you can see that the new menu item has been added to the main menu: ![bookstore-menu-items](images/bookstore-new-menu-item.png) -When you click to the Books menu item under the Book Store parent, you are being redirected to the new empty Books Page. +When you click on the Books menu item under the Book Store parent, you will be redirected to the new empty Books Page. ### Book List -We will use the [Datatables.net](https://datatables.net/) jQuery library to show the book list. Datatables library completely work via AJAX, it is fast, popular and provides a good user experience. +We will use the [Datatables.net](https://datatables.net/) jQuery library to show the book list. Datatables library completely works via AJAX, it is fast, popular and provides a good user experience. -> Datatables library 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. +> Datatables library is configured in the startup template, so you can directly use it in any page without including any style or script file for your page. #### Index.cshtml -Change the `Pages/Books/Index.cshtml` as following: +Change the `Pages/Books/Index.cshtml` as the following: ````html @page @@ -250,8 +250,8 @@ Change the `Pages/Books/Index.cshtml` as following: ```` -* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro) is used to add external **scripts** to the page. It has many additional features compared to standard `script` tag. It handles **minification** and **versioning**. See the [bundling & minification document](../UI/AspNetCore/Bundling-Minification.md) for details. -* `abp-card` is a tag helper for Twitter Bootstrap's [card component](https://getbootstrap.com/docs/4.5/components/card/). There are other useful tag helpers provided by the ABP Framework to easily use most of the [bootstrap](https://getbootstrap.com/) components. You could use the regular HTML tags instead of these tag helpers, but using tag helpers reduces HTML code and prevents errors by help the of IntelliSense and compile time type checking. Further information, see the [tag helpers](../UI/AspNetCore/Tag-Helpers/Index.md) document. +* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro) is used to add external **scripts** to the page. It has many additional features compared to the standard `script` tag. It handles **minification** and **versioning**. Check the [bundling & minification document](../UI/AspNetCore/Bundling-Minification.md) for details. +* `abp-card` is a tag helper for Twitter Bootstrap's [card component](https://getbootstrap.com/docs/4.5/components/card/). There are other useful tag helpers provided by the ABP Framework to easily use most of [bootstrap](https://getbootstrap.com/)'s components. You could use the regular HTML tags instead of these tag helpers, but using tag helpers reduces HTML code and prevents errors by the help of the IntelliSense and compiles time type checking. For further information, check the [tag helpers](../UI/AspNetCore/Tag-Helpers/Index.md) document. #### Index.js @@ -316,9 +316,9 @@ $(function () { }); ```` -* `abp.localization.getResource` gets a function that is used to localize text using the same JSON file defined in the server side. In this way, you can share the localization values with the client side. +* `abp.localization.getResource` gets a function that is used to localize text using the same JSON file defined on the server side. In this way, you can share the localization values with the client side. * `abp.libs.datatables.normalizeConfiguration` is a helper function defined by the ABP Framework. There's no requirement to use it, but it simplifies the [Datatables](https://datatables.net/) configuration by providing conventional default values for missing options. -* `abp.libs.datatables.createAjax` is another helper function to adapt ABP's dynamic JavaScript API proxies to [Datatable](https://datatables.net/)'s expected parameter format +* `abp.libs.datatables.createAjax` is another helper function to adapt the ABP's dynamic JavaScript API proxies to the [Datatable](https://datatables.net/)'s expected parameter format * `acme.bookStore.books.book.getList` is the dynamic JavaScript proxy function introduced before. * [luxon](https://moment.github.io/luxon/) library is also a standard library that is pre-configured in the solution, so you can use to perform date/time operations easily. @@ -336,9 +336,9 @@ This is a fully working, server side paged, sorted and localized table of books. ## Install NPM packages -> Notice: This tutorial is based on the ABP Framework v3.1.0+ If your project version is older, then please upgrade your solution. See the [migration guide](../UI/Angular/Migration-Guide-v3.md) if you are upgrading an existing project with v2.x. +> Notice: This tutorial is based on the ABP Framework v3.1.0+ If your project version is older, then please upgrade your solution. Check the [migration guide](../UI/Angular/Migration-Guide-v3.md) if you are upgrading an existing project with v2.x. -If you haven't done it before, open a new command line interface (terminal window) and go to your `angular` folder and then run `yarn` command to install the NPM packages: +If you haven't done it before, open a new command line interface (terminal window) and go to your `angular` folder and then run the `yarn` command to install the NPM packages: ```bash yarn @@ -400,7 +400,7 @@ export class BookModule { } ### Routing -Generated code places the new route definition to the `src/app/app-routing.module.ts` file as shown below: +The generated code places the new route definition to the `src/app/app-routing.module.ts` file as shown below: ````js const routes: Routes = [ @@ -409,7 +409,7 @@ const routes: Routes = [ ]; ```` -Now, open the `src/app/route.provider.ts` file replace the `configureRoutes` function declaration as shown below: +Now, open the `src/app/route.provider.ts` file and replace the `configureRoutes` function declaration as shown below: ```js function configureRoutes(routes: RoutesService) { @@ -443,18 +443,18 @@ function configureRoutes(routes: RoutesService) { `RoutesService` is a service provided by the ABP Framework to configure the main menu and the routes. * `path` is the URL of the route. -* `name` is the localized menu item name (see the [localization document](../UI/Angular/Localization.md) for details). +* `name` is the localized menu item name (check the [localization document](../UI/Angular/Localization.md) for details). * `iconClass` is the icon of the menu item (you can use [Font Awesome](https://fontawesome.com/) icons by default). * `order` is the order of the menu item. * `layout` is the layout of the BooksModule's routes (there are three types of pre-defined layouts: `eLayoutType.application`, `eLayoutType.account` or `eLayoutType.empty`). -For more information, see the [RoutesService document](../UI/Angular/Modifying-the-Menu.md#via-routesservice). +For more information, check the [RoutesService document](../UI/Angular/Modifying-the-Menu.md#via-routesservice). ### Service Proxy Generation -[ABP CLI](../CLI.md) provides `generate-proxy` command that generates client proxies for your HTTP APIs to make easy to consume your HTTP APIs from the client side. Before running `generate-proxy` command, your host must be up and running. +[ABP CLI](../CLI.md) provides a `generate-proxy` command that generates client proxies for your HTTP APIs to make your HTTP APIs easy to consume by the client side. Before running the `generate-proxy` command, your host must be up and running. -> **Warning**: There is a problem with IIS Express; it doesn't allow to connect to the application from another process. If you are using Visual Studio, select the `Acme.BookStore.HttpApi.Host` instead of IIS Express in the run button drop-down list, as shown in the figure below: +> **Warning**: There is a problem with IIS Express; it doesn't allow connecting to the application from another process. If you are using Visual Studio, select the `Acme.BookStore.HttpApi.Host` instead of IIS Express in the run button drop-down list, as shown in the figure below: ![vs-run-without-iisexpress](images/vs-run-without-iisexpress.png) @@ -499,9 +499,9 @@ export class BookComponent implements OnInit { ``` * We imported and injected the generated `BookService`. -* We are using the [ListService](../UI/Angular/List-Service.md), a utility service of the ABP Framework which provides easy pagination, sorting and searching. +* We are using the [ListService](../UI/Angular/List-Service.md), a utility service from the ABP Framework which provides easy pagination, sorting and searching. -Open the `/src/app/book/book.component.html` and replace the content as below: +Open the `/src/app/book/book.component.html` and replace the content as shown below: ```html
    @@ -546,7 +546,7 @@ Now you can see the final result on your browser: ## Create a Books Page -It's time to create something visible and usable! Right click to the `Pages` folder under the `Acme.BookStore.Blazor` project and add a new **razor component**, named `Books.razor`: +It's time to create something visible and usable! Right click on the `Pages` folder under the `Acme.BookStore.Blazor` project and add a new **razor component**, named `Books.razor`: ![blazor-add-books-component](images/blazor-add-books-component.png) @@ -562,7 +562,7 @@ Replace the contents of this component as shown below: } ```` -### Add Books Page to the Main Menu +### Add the Books Page to the Main Menu Open the `BookStoreMenuContributor` class in the `Blazor` project add the following code to the end of the `ConfigureMainMenuAsync` method: @@ -582,17 +582,17 @@ context.Menu.AddItem( ); ```` -Run the project, login to the application with the username `admin` and the password `1q2w3E*` and see the new menu item has been added to the main menu: +Run the project, login to the application with the username `admin` and the password `1q2w3E*` and see that the new menu item has been added to the main menu: ![blazor-menu-bookstore](images/blazor-menu-bookstore.png) -When you click to the Books menu item under the Book Store parent, you are being redirected to the new empty Books Page. +When you click on the Books menu item under the Book Store parent, you will be redirected to the new empty Books Page. ### Book List -We will use the [Blazorise library](https://blazorise.com/) as the UI component kit. It is a very powerful library that supports major HTML/CSS frameworks, including the Bootstrap. +We will use the [Blazorise library](https://blazorise.com/) as the UI component kit. It is a very powerful library that supports major HTML/CSS frameworks, including Bootstrap. -ABP Framework provides a generic base class, `AbpCrudPageBase<...>`, to create CRUD style pages. This base class is compatible to the `ICrudAppService` that was used to build the `IBookAppService`. So, we can inherit from the `AbpCrudPageBase` to automate the code behind for the standard CRUD stuff. +ABP Framework provides a generic base class - `AbpCrudPageBase<...>`, to create CRUD style pages. This base class is compatible with the `ICrudAppService` that was used to build the `IBookAppService`. So, we can inherit from the `AbpCrudPageBase` to automate the code behind for the standard CRUD stuff. Open the `Books.razor` and replace the content as the following: @@ -651,17 +651,17 @@ Open the `Books.razor` and replace the content as the following: ```` -> If you see some syntax errors, you can ignore them if your application properly built and run. Visual Studio still has some bugs with Blazor. +> If you see some syntax errors, you can ignore them if your application is properly built and running. Visual Studio still has some bugs with Blazor. -* Inherited from the `AbpCrudPageBase` which implements all the CRUD details for us. +* Inherited from `AbpCrudPageBase` which implements all the CRUD details for us. * `Entities`, `TotalCount`, `PageSize`, `OnDataGridReadAsync` are defined in the base class. * Injected `IStringLocalizer` (as `L` object) and used for localization. -While the code above pretty easy to understand, you can check the Blazorise [Card](https://blazorise.com/docs/components/card/) and [DataGrid](https://blazorise.com/docs/extensions/datagrid/) documents to understand them better. +While the code above is pretty easy to understand, you can check the Blazorise [Card](https://blazorise.com/docs/components/card/) and [DataGrid](https://blazorise.com/docs/extensions/datagrid/) documents to understand them better. #### About the AbpCrudPageBase -We will continue to benefit from the `AbpCrudPageBase` for the books page. You could just inject the `IBookAppService` and perform all the server side calls yourself (thanks to the [Dynamic C# HTTP API Client Proxy](../API/Dynamic-CSharp-API-Clients.md) system of the ABP Framework). We will do it manually for the authors page to demonstrate how to call server side HTTP APIs in your Blazor applications. +We will continue benefitting from `AbpCrudPageBase` for the books page. You could just inject the `IBookAppService` and perform all the server side calls yourself (thanks to the [Dynamic C# HTTP API Client Proxy](../API/Dynamic-CSharp-API-Clients.md) system of the ABP Framework). We will do it manually for the authors page to demonstrate how to call the server side HTTP APIs in your Blazor applications. ## Run the Final Application @@ -675,4 +675,4 @@ This is a fully working, server side paged, sorted and localized table of books. ## The Next Part -See the [next part](Part-3.md) of this tutorial. +Check the [next part](Part-3.md) of this tutorial. From f44022e23660804889f8c7b785789a4657db3678 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 4 Jan 2022 10:15:20 +0800 Subject: [PATCH 10/18] Run Gulp when gulpfile exist --- .../Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs index 4530b59142..e1a048b9e1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs @@ -88,7 +88,7 @@ namespace Volo.Abp.Cli.ProjectModification RunYarn(fileDirectory); } - if (!IsAngularProject(fileDirectory)) + if (!IsAngularProject(fileDirectory) && GulpFileExistAsync(fileDirectory)) { Thread.Sleep(1000); RunGulp(fileDirectory); @@ -108,6 +108,11 @@ namespace Volo.Abp.Cli.ProjectModification return await Task.FromResult(File.Exists(Path.Combine(directoryName, ".npmrc"))); } + private static bool GulpFileExistAsync(string directoryName) + { + return File.Exists(Path.Combine(directoryName, "gulpfile.js")); + } + private async Task CreateNpmrcFileAsync(string directoryName) { var fileName = Path.Combine(directoryName, ".npmrc"); From db01ccce1e48cbaf1faee27465f94877ee843ab8 Mon Sep 17 00:00:00 2001 From: Enis Necipoglu Date: Tue, 4 Jan 2022 08:04:27 +0300 Subject: [PATCH 11/18] Update docs/en/Modules/Cms-Kit/Index.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Halil İbrahim Kalkan --- docs/en/Modules/Cms-Kit/Index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index fc28736a70..7d773973e0 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -22,7 +22,7 @@ All features are individually usable. If you disable a feature, it completely di CMS Kit uses [distributed cache](../../Caching.md) for responding faster. -> Using a distributed cache such as [Redis](../../Redis-Cache.md) is highly recommended for data consistency in tiered solutions. +> Using a distributed cache, such as [Redis](../../Redis-Cache.md), is highly recommended for data consistency in distributed/clustered deployments. ## How to Install From 470deed1d72bb5d1183847559c672cd91b5bb1ff Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 4 Jan 2022 15:18:25 +0800 Subject: [PATCH 12/18] Use Dynamic proxy in template by default --- .../MyCompanyName.MyProjectName.Web.Host.csproj | 2 +- .../MyProjectNameWebModule.cs | 3 +-- .../MyCompanyName.MyProjectName.Web.Host.csproj | 1 + .../MyProjectNameWebHostModule.cs | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj index 8ecfbf8fe7..c90a667f14 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj @@ -29,11 +29,11 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs index 206e47abd9..31b20171bb 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs @@ -29,7 +29,6 @@ using Volo.Abp.AutoMapper; using Volo.Abp.Caching; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Http.Client.IdentityModel.Web; -using Volo.Abp.Http.Client.Web; using Volo.Abp.Identity.Web; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; @@ -46,13 +45,13 @@ namespace MyCompanyName.MyProjectName.Web { [DependsOn( typeof(MyProjectNameHttpApiClientModule), + typeof(MyProjectNameHttpApiModule), typeof(AbpAspNetCoreAuthenticationOpenIdConnectModule), typeof(AbpAspNetCoreMvcClientModule), typeof(AbpAspNetCoreMvcUiBasicThemeModule), typeof(AbpAutofacModule), typeof(AbpCachingStackExchangeRedisModule), typeof(AbpSettingManagementWebModule), - typeof(AbpHttpClientWebModule), typeof(AbpHttpClientIdentityModelWebModule), typeof(AbpIdentityWebModule), typeof(AbpTenantManagementWebModule), diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj index 9536fdce15..29ab15443c 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj @@ -34,6 +34,7 @@ + diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs index df87db8359..58c5b42c7a 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs @@ -34,7 +34,6 @@ using Volo.Abp.Caching; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.FeatureManagement; using Volo.Abp.Http.Client.IdentityModel.Web; -using Volo.Abp.Http.Client.Web; using Volo.Abp.Identity; using Volo.Abp.Identity.Web; using Volo.Abp.Modularity; @@ -55,12 +54,12 @@ namespace MyCompanyName.MyProjectName [DependsOn( typeof(MyProjectNameWebModule), typeof(MyProjectNameHttpApiClientModule), + typeof(MyProjectNameHttpApiModule), typeof(AbpAspNetCoreAuthenticationOpenIdConnectModule), typeof(AbpAspNetCoreMvcClientModule), typeof(AbpAspNetCoreMvcUiBasicThemeModule), typeof(AbpAutofacModule), typeof(AbpCachingStackExchangeRedisModule), - typeof(AbpHttpClientWebModule), typeof(AbpHttpClientIdentityModelWebModule), typeof(AbpIdentityWebModule), typeof(AbpIdentityHttpApiClientModule), From f3e25dc756f4779e54e6b39e31e9b71fc1848e04 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 4 Jan 2022 16:04:32 +0800 Subject: [PATCH 13/18] Update Authorization.md --- docs/en/Authorization.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md index 66fded1a29..d96879c296 100644 --- a/docs/en/Authorization.md +++ b/docs/en/Authorization.md @@ -428,7 +428,7 @@ This is already done for the startup template integration tests. Claims are important elements of authentication and authorization. ABP uses the `IAbpClaimsPrincipalFactory` service to create claims on authentication. This service was designed as extensible. If you need to add your custom claims to the authentication ticket, you can implement the `IAbpClaimsPrincipalContributor` in your application. -**Example: Add a `SocialSecurityNumber` claim:** +**Example: Add a `SocialSecurityNumber` claim and get it:** ```csharp public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency @@ -448,6 +448,15 @@ public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipa } } } + + +public static class CurrentUserExtensions +{ + public static stromg GetSocialSecurityNumber(ICurrentUser currentUser) + { + return currentUser.FindClaimValue("SocialSecurityNumber"); + } +} ``` ## See Also From 18762d08e6f11688e5dccdd1460b1a294b48e6a8 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 4 Jan 2022 16:05:05 +0800 Subject: [PATCH 14/18] Update Authorization.md --- docs/en/Authorization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md index d96879c296..0d27d08403 100644 --- a/docs/en/Authorization.md +++ b/docs/en/Authorization.md @@ -452,7 +452,7 @@ public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipa public static class CurrentUserExtensions { - public static stromg GetSocialSecurityNumber(ICurrentUser currentUser) + public static string GetSocialSecurityNumber(ICurrentUser currentUser) { return currentUser.FindClaimValue("SocialSecurityNumber"); } From 80d1687f96a05852879b7f765ef46707ac3eea92 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 4 Jan 2022 16:08:46 +0800 Subject: [PATCH 15/18] Add this to the extension method. --- docs/en/Authorization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md index 0d27d08403..199b73d1c8 100644 --- a/docs/en/Authorization.md +++ b/docs/en/Authorization.md @@ -452,7 +452,7 @@ public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipa public static class CurrentUserExtensions { - public static string GetSocialSecurityNumber(ICurrentUser currentUser) + public static string GetSocialSecurityNumber(this ICurrentUser currentUser) { return currentUser.FindClaimValue("SocialSecurityNumber"); } From 00511943ed88501026c19160d4614378d507efd7 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Tue, 4 Jan 2022 13:33:43 +0300 Subject: [PATCH 16/18] Set version from MicrosoftPackageVersion variable. Manual version breaks nightly builds. --- .../Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj index 918ac8ddf3..23ef9a5f0c 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj @@ -20,7 +20,7 @@ - + From 7cc6dea0ea7aaba708df01e600c3cf59aecb1c85 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Tue, 4 Jan 2022 14:04:50 +0300 Subject: [PATCH 17/18] remove already referenced package references by third party libs --- .../Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj | 1 - .../Volo.Abp.EntityFrameworkCore.Oracle.csproj | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj index 23ef9a5f0c..3bb22e24d8 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj @@ -20,7 +20,6 @@ - diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj index abfb6e41a1..7d99c2035b 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj @@ -19,8 +19,7 @@ - - + From 5504de63d286b5edc55ce7c04b95d3c3b61f84d5 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Tue, 4 Jan 2022 15:24:55 +0300 Subject: [PATCH 18/18] Delete 0 --- nupkg/0 | Bin 8 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 nupkg/0 diff --git a/nupkg/0 b/nupkg/0 deleted file mode 100644 index cf175e3b0b668a96032b3e0d45584039f893e6a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 PcmezW&wzoKfr|kE5LyC7