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




