Browse Source

Updated tutorial for the v0.3.5. release.

pull/341/head
Halil ibrahim Kalkan 8 years ago
parent
commit
458b503dbd
  1. 34
      docs/Tutorials/AspNetCore-Mvc/Part-I.md
  2. 173
      docs/Tutorials/AspNetCore-Mvc/Part-II.md
  3. 17
      docs/Tutorials/AspNetCore-Mvc/Part-III.md

34
docs/Tutorials/AspNetCore-Mvc/Part-I.md

@ -1,6 +1,6 @@
## ASP.NET Core MVC Tutorial - Part I ## ASP.NET Core MVC Tutorial - Part I
### About the 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 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: `index.js` content is shown below:
````js ````js
$(function() { $(function () {
var dataTable = $('#BooksTable').DataTable({ var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({
ajax: abp.libs.datatables.createAjax(acme.bookStore.book.getList), ajax: abp.libs.datatables.createAjax(acme.bookStore.book.getList),
columnDefs: [ columnDefs: [
{ { data: "name" },
targets: 0, { data: "type" },
data: "name" { data: "publishDate" },
}, { data: "price" },
{ { data: "creationTime" }
targets: 1,
data: "type"
},
{
targets: 2,
data: "publishDate"
},
{
targets: 3,
data: "price"
},
{
targets: 4,
data: "creationTime"
}
] ]
}); }));
}); });
```` ````
* `abp.libs.datatables.createAjax` is a helper function to adapt ABP's dynamic JavaScript API proxies to Datatable's format. * `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). * `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. * See [Datatable's documentation](https://datatables.net/manual/) for more configuration options.

173
docs/Tutorials/AspNetCore-Mvc/Part-II.md

@ -1,8 +1,6 @@
## ASP.NET Core MVC Tutorial - Part II ## ASP.NET Core MVC Tutorial - Part II
### About the 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).
This is the second part of the tutorial series. See all parts: 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
````C# ````C#
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace Acme.BookStore.Pages.Books namespace Acme.BookStore.Pages.Books
{ {
@ -56,7 +53,7 @@ namespace Acme.BookStore.Pages.Books
} }
```` ````
* 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. * `[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. * 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. * 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. * `abp-model` attribute indicates the model object, the `Book` property in this case.
* `data-ajaxForm` attribute makes the form to submit via AJAX, instead of 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. This is optional and needed only if you added some other content in the `abp-dynamic-form` tag. * `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).
#### Add the "New book" Button #### Add the "New book" Button
@ -179,7 +176,7 @@ namespace Acme.BookStore.Pages.Books
} }
```` ````
* `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. * 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.
@ -270,7 +267,7 @@ Open the `Pages/Books/Index.cshtml` page and change the table section as shown b
</abp-table> </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: 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 createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');
var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal'); var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal');
var dataTable = $('#BooksTable').DataTable({ var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({
order: [[1, "asc"]], order: [[1, "asc"]],
ajax: abp.libs.datatables.createAjax(acme.bookStore.book.getList), ajax: abp.libs.datatables.createAjax(acme.bookStore.book.getList),
columnDefs: [ columnDefs: [
{ {
targets: 0,
data: null,
orderable: false,
autoWidth: false,
defaultContent: '',
rowAction: { rowAction: {
text: '<i class="fa fa-cog"></i> ' + l('Actions') +
' <span class="caret"></span>',
items: items:
[ [
{ {
text: l('Edit'), text: l('Edit'),
visible: function () { return true; },
action: function (data) { action: function (data) {
editModal.open({ editModal.open({ id: data.record.id });
id: data.record.id
});
}
},
{
text: l('Delete'),
visible: function () { return true; },
confirmMessage: function (data) {
return l('BookDeletionConfirmationMessage',
data.record.name);
},
action: function (data) {
acme.bookStore.book
.delete(data.record.id)
.then(function () {
abp.notify.info(l('SuccessfullyDeleted'));
dataTable.ajax.reload();
});
} }
} }
] ]
} }
}, },
{ { data: "name" },
targets: 1, { data: "type" },
data: "name" { data: "publishDate" },
}, { data: "price" },
{ { data: "creationTime" }
targets: 2,
data: "type"
},
{
targets: 3,
data: "publishDate"
},
{
targets: 4,
data: "price"
},
{
targets: 5,
data: "creationTime"
}
] ]
}); }));
createModal.onResult(function () { createModal.onResult(function () {
dataTable.ajax.reload(); dataTable.ajax.reload();
@ -363,7 +319,104 @@ $(function () {
}); });
```` ````
* Used `abp.localization.getResource('BookStore')` to be able to use the same localization texts defined on the server side.
* Added a new `ModalManager` named `editModal` to open the edit modal dialog. * Added a new `ModalManager` named `editModal` to open the edit modal dialog.
* Added a new column at the beginning of the `columnDefs` section. This column is used for the "Actions" dropdown button. * Added a new column at the beginning of the `columnDefs` section. This column is used for the "Actions" dropdown button.
* "Edit" action simply calls `editModal.open` to open the edit dialog. * "Edit" action simply calls `editModal.open` to open the edit dialog.
* Also added a "Delete" button to delete the book.
You can run the application and edit any book by selecting the edit action.
### Deleting an Existing Book
Open the `wwwroot/pages/books/index.js` and add a new item to the `rowAction` `items`:
````js
{
text: l('Delete'),
confirmMessage: function (data) {
return l('BookDeletionConfirmationMessage', data.record.name);
},
action: function (data) {
acme.bookStore.book
.delete(data.record.id)
.then(function() {
abp.notify.info(l('SuccessfullyDeleted'));
dataTable.ajax.reload();
});
}
}
````
* `confirmMessage` option is used to ask a confirmation question before executing the `action`.
* Used `acme.bookStore.book.delete` javascript proxy function to perform an AJAX request to delete a book.
* `abp.notify.info` is used to show a toastr notification just after the deletion.
The final `index.js` content is shown below:
````js
$(function () {
var l = abp.localization.getResource('BookStore');
var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');
var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal');
var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({
order: [[1, "asc"]],
ajax: abp.libs.datatables.createAjax(acme.bookStore.book.getList),
columnDefs: [
{
rowAction: {
items:
[
{
text: l('Edit'),
action: function (data) {
editModal.open({ id: data.record.id });
}
},
{
text: l('Delete'),
confirmMessage: function (data) {
return l('BookDeletionConfirmationMessage', data.record.name);
},
action: function (data) {
acme.bookStore.book
.delete(data.record.id)
.then(function() {
abp.notify.info(l('SuccessfullyDeleted'));
dataTable.ajax.reload();
});
}
}
]
}
},
{ data: "name" },
{ data: "type" },
{ data: "publishDate" },
{ data: "price" },
{ data: "creationTime" }
]
}));
createModal.onResult(function () {
dataTable.ajax.reload();
});
editModal.onResult(function () {
dataTable.ajax.reload();
});
$('#NewBookButton').click(function (e) {
e.preventDefault();
createModal.open();
});
});
````
Run the application and try to delete a book.
### Next Part
See the [next part](Part-III.md) of this tutorial.

17
docs/Tutorials/AspNetCore-Mvc/Part-III.md

@ -1,8 +1,6 @@
## ASP.NET Core MVC Tutorial - Part III ## ASP.NET Core MVC Tutorial - Part III
### About the 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).
This is the third part of the tutorial series. See all parts: This is the third part of the tutorial series. See all parts:
@ -18,10 +16,10 @@ There are two test projects in the solution:
![bookstore-test-projects](images/bookstore-test-projects.png) ![bookstore-test-projects](images/bookstore-test-projects.png)
* `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.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 too. * `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. * [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.
@ -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: 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 ### 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`.
### Testing Web Pages ### Testing Web Pages

Loading…
Cancel
Save