ASP.net Core APP 03 – Cadastro de produtos

O objetivo deste tutorial é construir uma tela de cadastro de produtos, que posteriormente será transformada em uma tela de cadastro complexa (Pai/Filho), permitindo vincular características aos produtos cadastrados. Para isso o primeiro passo é criar dentro da pasta Controllers do projeto uma nova classe chamada ProductController, nela vamos criar duas actions Index e Form.

using Microsoft.AspNetCore.Mvc;

namespace myshop.Controllers
{
    public class ProductController  : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
        public IActionResult Form()
        {
            return View();
        }

    }
}

Agora dentro da pasta Views vamos criar uma nova subpasta chamada Product. Nesta pasta vamos criar as interfaces do controlador Product.

Crie um novo arquivo com o nome Form.cshtml e utilize o código de exemplo abaixo como base.

<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="max-age=604800" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="author" content="Bootstrap-ecommerce by Vosidiy">
 
<title>UI KIT - Marketplace and Ecommerce html template</title>
 
<link href="/images/favicon.ico" rel="shortcut icon" type="image/x-icon">
 
<!-- jQuery -->
<script src="/js/jquery-2.0.0.min.js" type="text/javascript"></script>
 
<!-- Bootstrap4 files-->
<script src="/js/bootstrap.bundle.min.js" type="text/javascript"></script>
<link href="/css/bootstrap.css" rel="stylesheet" type="text/css"/>
 
<!-- Font awesome 5 -->
<link href="/fonts/fontawesome/stylesheets/fontawesome-all.min.css" type="text/css" rel="stylesheet">
 
<!-- custom style -->
<link href="/css/ui.css" rel="stylesheet" type="text/css"/>
<link href="/css/responsive.css" rel="stylesheet" media="only screen and (max-width: 1200px)" />
 
<!-- custom javascript -->
<script src="/js/script.js" type="text/javascript"></script>
 
<script type="text/javascript">
/// some script
 
// jquery ready start
$(document).ready(function() {
    // jQuery code
 
}); 
// jquery end
</script>
 
</head>
<body>
<header class="section-header">
<nav class="navbar navbar-top navbar-expand-lg navbar-dark bg-secondary">
<div class="container">
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNav">
    <ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="http://bootstrap-ecommerce.com">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item"><a class="nav-link" href="html-components.html"> Documentation </a></li>
<li class="nav-item dropdown">
    <a class="nav-link  dropdown-toggle" href="#" data-toggle="dropdown">  Dropdown  </a>
    <ul class="dropdown-menu">
      <li><a class="dropdown-item" href="#"> Menu item 1</a></li>
      <li><a class="dropdown-item" href="#"> Menu item 2 </a></li>
    </ul>
</li>
<li class="nav-item"><a class="nav-link" href="http://bootstrap-ecommerce.com"> Download <i class="fa fa-download"></i></a></li>
    </ul>
  </div>
</div> <!-- container //  -->
</nav>
<section class="header-main shadow">
    <div class="container">
<div class="row align-items-center">
    <div class="col-lg-3 col-sm-4">
    <div class="brand-wrap">
        <img class="logo" src="images/logo-dark.png">
        <h2 class="logo-text">LOGO</h2>
    </div> <!-- brand-wrap.// -->
    </div>
    <div class="col-lg-6 col-sm-8">
             
    </div> <!-- col.// -->
    <div class="col-lg-3 col-sm-12">
            <a href="#" class="widget-header float-md-right">
                <div class="icontext">
                    <div class="icon-wrap"><i class="flip-h fa-lg fa fa-phone"></i></div>
                    <div class="text-wrap">
                        <small>Phone</small>
                        <div>+97150 2813773</div>
                    </div>
                </div>
            </a>
    </div> <!-- col.// -->
</div> <!-- row.// -->
    </div> <!-- container.// -->
</section> <!-- header-main .// -->
</header> <!-- section-header.// -->
 
<!-- ========================= SECTION PAGETOP ========================= -->
<section class="section-pagetop bg-secondary">
<div class="container clearfix">
    <h2 class="title-page">Produto</h2>
</div> <!-- container //  -->
</section>
<!-- ========================= SECTION INTRO END// ========================= -->
 
<!-- ========================= SECTION CONTENT ========================= -->
<section class="section-content bg padding-y">
<div class="container">
 
<div class="row">
    <main class="col-sm-9">
 
<article class="card">
    <div class="card-body">
        <form action = "/product/save" method="POST">
          <div class="form-group">
            <label for="inputName">Nome</label>
            <input type="text" class="form-control" id="inputName" name="name" placeholder="Nome do produto">
          </div>
          <div class="form-group">
            <label for="inputDesc">Descrição</label>
            <textarea rows="5" cols="33" class="form-control" id="inputDesc" name="description" placeholder="Descrição do produto"></textarea>
          </div>
          <div class="form-group">
            <label for="inputPrice">Preço</label>
            <input type="number" min="0" max="1000" step="0.25" class="form-control" id="inputPrice"  name="price" placeholder="Preço do produto">
          </div>
          <button type="submit" class="btn btn-primary">Salvar</button>
        </form>
    </div> <!-- card-body .// -->
</article> <!-- card product .// -->
 
 
 
    </main> <!-- col.// -->
</div>
 
</div> <!-- container .//  -->
</section>
<!-- ========================= SECTION CONTENT END// ========================= -->
 
 
 
<!-- ========================= FOOTER ========================= -->
<footer class="section-footer bg-secondary">
    <div class="container">
        <section class="footer-top padding-top">
             
        </section> <!-- //footer-top -->
    </div><!-- //container -->
</footer>
<!-- ========================= FOOTER END // ========================= -->
 
 
</body>
</html>

Em seguida utilize o comando dotnet run e acesse o endereço https://localhost:5001/product/form para verificar se a interface gráfica abaixo é carregada.

Agora vamos modificar nosso formulário para enviar os dados para o controlador. Para isso vamos utilizar o RAZOR para gerar o código HTML do formulário. No topo do arquivo Form.cshtml inclua o decorator @model para vincular a classe Product como model desta view. IMPORTANTE: caso sua aplicação tenha outro nome substitua myshop pelo nome da sua aplicação.

@model myshop.Models.Product;

Agora procure no código da view pela tag form. Vamos modificar o código dela primeiro substituindo o form tradicional pelo decorator @using e a classe helper Html.BeginForm para que os dados do formulário sejam enviados para o controlador Product na nova action que vamos escrever. Vamos também substituir os tags do formulário pelos helpers do Razor para gerar os campos do formulário.

@using (Html.BeginForm("Form","Product")){
        <!--<form action = "/product/save" method="POST">-->
          @Html.HiddenFor(m => m.Id)
          <div class="form-group">
              @Html.LabelFor(m => m.Name)
              @Html.EditorFor(m => m.Name, new { htmlAttributes = new { @class = "form-control" }})
              @Html.ValidationMessageFor(m => m.Name)
          </div>
          <div class="form-group">
              @Html.LabelFor(m => m.Description)
              @Html.EditorFor(m => m.Description, new { htmlAttributes = new { @class = "form-control" }})
              @Html.ValidationMessageFor(m => m.Description)
          </div>
          <div class="form-group">
              @Html.LabelFor(m => m.Price)
              @Html.EditorFor(m => m.Price, new { htmlAttributes = new { @class = "form-control" }})
              @Html.ValidationMessageFor(m => m.Price)
          </div>          
          <button type="submit" class="btn btn-primary">Salvar</button>
        <!--</form>-->
        }

Agora que a nossa interface esta pronta vamos altera nossa classe ProductController para criar as novas actions necessárias para tratar o formulário. Observe que sobre as Actions Index() e Form() incluímos o decorador [HttpGet] para indicar que eles serão chamados quando o controlador receber uma requisição do tipo GET. Criamos uma sobrecarga do método Form(Product product) recebendo a instância da classe produto e anotamos com [HttpPost]. Execute a aplicação acesse o formulário e envie dados, depois verifique no console se o nome do produto é apresentado.

using System;
using Microsoft.AspNetCore.Mvc;
using myshop.Models;

namespace myshop.Controllers
{
    public class ProductController  : Controller
    {
        [HttpGet]
        public IActionResult Index()
        {
            return View();
        }
        [HttpGet]
        public IActionResult Form()
        {
            return View();
        }
        [HttpPost]
        public IActionResult Form(Product product){
            Console.WriteLine(product.Name);
            return View();
        }
    }
}

Agora devemos construir um novo método em nossa interface IProductService para permitir que os dados do produto sejam salvos no banco de dados.

using System.Collections.Generic;
using myshop.Models;

namespace myshop.Services
{
    public interface IProductService
    {
         List<Product> GetAll();
         List<Product> GetAllByName(string name);
         void save(Product product);
    }
}

Em seguida vamos implementar o código deste método dentro da nossa classe de ProductService. Aproveitando a implementação do método já vamos deixar ele pronto para tanto incluir um novo produto quando enviar uma ação de atualização dos dados de um produto já existente.

using System;
using System.Collections.Generic;
using MongoDB.Bson;
using MongoDB.Driver;
using myshop.Models;

namespace myshop.Services
{
    public class ProductService : IProductService
    {
        MongoClient con;
        IMongoDatabase db;
        public ProductService()
        {
            con = new MongoClient("mongodb://172.18.0.35:27017");
            db = con.GetDatabase("dbwalter");
            if(db.GetCollection<Product>("Products") == null)
                db.CreateCollection("Products");
        }
        public List<Product> GetAll()
        {
            var collection = db.GetCollection<Product>("Products");
            return collection.Find<Product>(p => true).ToList();
        }
        public List<Product> GetAllByName(string name){
            var collection = db.GetCollection<Product>("Products");
            return collection.Find<Product>(p => p.Name.ToLower().Contains(name.ToLower())).ToList();
        }

        public void save(Product product)
        {
            var collection = db.GetCollection<Product>("Products");
            if(product.Id == null | product.Id == String.Empty)
                collection.InsertOne(product);
            else{
                var filter = Builders<Product>.Filter.Eq("Id", product.Id);
                var updateDefinition = Builders<Product>.Update
                        .Set(p => p.Name, product.Name)
                        .Set(p => p.Description, product.Description)
                        .Set(p => p.Price, product.Price);
                collection.UpdateOne(filter,updateDefinition);
            }
        }
    }
}

Para concluir, vamos alterar nossa class ProductController para criar um construtor e receber a instância do ProductService por injeção de dependência.

E ainda nesta classe ProductController modificar o método Form(Product product) para verficar se os dados do formulário estão válidos e então chamar o método save do serviço.

using System;
using Microsoft.AspNetCore.Mvc;
using myshop.Models;
using myshop.Services;

namespace myshop.Controllers
{
    public class ProductController  : Controller
    {
        private IProductService productService;
        public ProductController(IProductService productService)
        {
            this.productService = productService;
        }
        [HttpGet]
        public IActionResult Index()
        {
            return View();
        }
        [HttpGet]
        public IActionResult Form()
        {
            return View();
        }
        [HttpPost]
        public IActionResult Form(Product product){
            if (ModelState.IsValid)
            {
                this.productService.save(product);
                return RedirectToAction("Index");
            }
            return View(product);
        }
    }
}