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);
}
}
}