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)).
@ -400,36 +400,22 @@ Create `index.js` JavaScript file under the `wwwroot/pages/books/` folder:
`index.js` content is shown below:
````js
$(function() {
var dataTable = $('#BooksTable').DataTable({
$(function() {
var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({
* `abp.libs.datatables.createAjax` is a helper function to adapt ABP's dynamic JavaScript API proxies to Datatable's format.
* `abp.libs.datatables.normalizeConfiguration` is another helper function. It's not required to use it, but it simplifies the datatables configuration by providing conventional values for missing options.
* `acme.bookStore.book.getList` is the function to get list of books (you have seen it before).
* See [Datatable's documentation](https://datatables.net/manual/) for more configuration options.
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).
### About this Tutorial
This is the second part of the tutorial series. See all parts:
@ -31,7 +29,6 @@ Open the `CreateModal.cshtml.cs` file (`CreateModalModel` class) and replace wit
* This class is derived from the `BookStorePageModelBase` instead of standard `PageModel`. `BookStorePageModelBase` inherits the `PageModel` and adds some common properties/methods those can be used in your page model classes.
* This class is derived from the `BookStorePageModelBase` instead of standard `PageModel`. `BookStorePageModelBase` inherits the `PageModel` and adds some common properties/methods those can be used by your page model classes.
* `[BindProperty]` attribute on the `Book` property binds post request data to this property.
* This class simply injects the `IBookAppService` in its constructor and calls the `CreateAsync` method in the `OnPostAsync` handler.
@ -84,9 +81,9 @@ 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.
* `abp-model` attribute indicates the model object, the `Book` in this case.
* `data-ajaxForm` attribute makes the form to submit via AJAX, instead of classic page post.
* `abp-form-content` tag helper is a placeholder to render the form. This is optional and needed only if you added some other content in the `abp-dynamic-form` tag.
* `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.
* `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).
* `HiddenInput` and `BindProperty` are standard ASP.NET Core MVC attributes. Used `SupportsGet` to be able to get Id value from query string parameter of the request.
* `[HiddenInput]` and `[BindProperty]` are standard ASP.NET Core MVC attributes. Used `SupportsGet` to be able to get Id value from query string parameter of the request.
* Mapped `BookDto` (received from the `BookAppService.GetAsync`) to `CreateUpdateBookDto` in the `GetAsync` method.
* The `OnPostAsync` simply uses `BookAppService.UpdateAsync` to update the entity.
@ -270,7 +267,7 @@ Open the `Pages/Books/Index.cshtml` page and change the table section as shown b
</abp-table>
````
* Just added a new `th` tag for the "Actions" button.
* Just added a new `th` tag for the "Actions".
Open the `wwwroot/pages/books/index.js` and replace the content as below:
@ -282,71 +279,30 @@ $(function () {
var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');
var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal');
var dataTable = $('#BooksTable').DataTable({
var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({
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).
### About this Tutorial
This is the third part of the tutorial series. See all parts:
@ -18,10 +16,10 @@ There are two test projects in the solution:
* `Acme.BookStore.Application.Tests` is for unit & integration test projects. You can write tests for application services those are integrated to the framework. It uses **EF Core SQLite in-memory** database.
* `Acme.BookStore.Web.Tests` is for full stack integration tests including the web layer. So, you can write tests for UI too.
* `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.
* `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 uses the following libraries for testing:
Test projects use the following libraries for testing:
* [xunit](https://xunit.github.io/) as the main test framework.
* [Shoudly](http://shouldly.readthedocs.io/en/latest/) as an assertion library.
@ -61,7 +59,8 @@ namespace Acme.BookStore
}
````
* It simply uses `IIdentityDataSeeder` which is implemented by the identity module and creates an admin role and admin user. You can use them in the tests.
* 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:
@ -123,7 +122,7 @@ namespace Acme.BookStore
}
````
* Injected `IRepository<Book, Guid>` and used it in the `BuildInternalAsync` to create 2 book entities.
* Injected `IRepository<Book, Guid>` and used it in the `BuildInternalAsync` to create two book entities.
### Testing the BookAppService
@ -211,7 +210,7 @@ public async Task Should_Not_Create_A_Book_Without_Name()
}
````
* Since the `Name` is set as empty, ABP throws an `AbpValidationException`.
* Since the `Name` is empty, ABP throws an `AbpValidationException`.