Versão
Idioma

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:

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:

livraria-criar-diálogo

Crie o formulário modal

Crie uma nova página de navalha, nomeada CreateModal.cshtmlsob a Pages/Bookspasta do Acme.BookStore.Webprojeto:

livraria-adicionar-criar-diálogo

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ão PageModel. BookStorePageModelherda o PageModele adiciona algumas propriedades / métodos comuns que podem ser usados pelas classes de modelo de página.
  • [BindProperty]O atributo na Bookpropriedade vincula os dados de solicitação posterior a essa propriedade.
  • Essa classe simplesmente injeta o IBookAppServiceem seu construtor e chama o CreateAsyncmétodo no OnPostAsyncmanipulador.
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-form
    

    auxiliar de marca para criar automaticamente o formulário a partir da

    CreateBookViewModel
    

    classe.

    • abp-modelO atributo indica o objeto do modelo, a Bookpropriedade neste caso.
    • data-ajaxForm O 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:

livraria-novo-livro-botão

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:

livraria-adicionar-editar-diálogo

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. Utilizado SupportsGetpara obter o valor do ID a partir do parâmetro da string de consulta da solicitação.
  • Mapeado BookDto(recebido de BookAppService.GetAsync) para CreateUpdateBookDtono GetAsyncmétodo
  • O OnPostAsyncsimplesmente usa BookAppService.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 a Idpropriedade 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:

livraria-livros-mesa-ações

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 ModalManagernome createModalpara abrir a caixa de diálogo criar modal.
  • Adicionado um novo ModalManagernome editModalpara 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 o action.
  • 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.

Esta página foi útil?
Por favor, faça uma seleção.
Obrigado pelo seu valioso feedback!

Observe que, embora não possamos responder aos comentários, nossa equipe usará seus comentários para melhorar a experiência.

Neste documento
Mastering ABP Framework Book
Dominando a estrutura ABP

Este livro o ajudará a obter uma compreensão completa da estrutura e das técnicas modernas de desenvolvimento de aplicativos da web.