I'm developing an e-commerce project in ASP.NET Core MVC 9, running on a Debian server. I have a form to register products, where I need to allow the user to select a gender for the product from a list of options loaded from the database.
In my RegisterProduct.cshtml View, I'm using radio buttons to display the gender options, inside a form that uses the asp-for Helper Tag to link the fields to the properties of my ProductModel. The list of genders is passed to the View through ViewBag.Genders, which contains a List<GenderModel>.
RegisterProduct.cshtml:
@model ProductModel
@{
Layout = "_Layout";
}
<div class="text-center">
<h1 class="display-4">Cadastrar Produto</h1>
<form asp-controller="Product" asp-action="Register" method="post" enctype="multipart/form-data">
<div class="form-group">
<label class="control-label">Imagens do Produto</label>
<input type="file" name="ProductImages" id="productImagesInput" class="form-control" multiple accept="image/*"/>
<div id="imagePreviewContainer" class="row mt-3">
@if (ViewBag.ImagePreviews != null) {
for (var i = 0; i < ((List<string>)ViewBag.ImagePreviews).Count; i++) {
<div class="image-preview-container" draggable="true" data-index="@i">
<img alt="" class="image-preview" src="@((List<string>)ViewBag.ImagePreviews)[i]"/>
</div>
}
}
</div>
</div>
<div class="form-group p-2">
<label for="name" class="control-label">Nome do Produto</label>
<input asp-for="ProductName" class="form-control" id="name" placeholder="Camisa Regular Em Sarja"/>
</div>
<div class="form-group p-2">
<label for="description" class="control-label">Descrição Curta</label>
<textarea asp-for="ProductDescription" class="form-control" id="description"
placeholder="Essa camisa regular em sarja oferece um visual clássico e confortável, ideal para diversas ocasiões. O tecido de sarja proporciona um toque macio e durabilidade, enquanto a modelagem regular garante um caimento solto e elegante."></textarea>
</div>
<div class="form-group p-2">
<label for="price" class="control-label">Valor</label>
<input type="number" min="0" step=".01" asp-for="ProductPrice" class="form-control" id="price"/>
</div>
<div class="form-group">
<div class="dropdown p-2">
<button class="btn btn-light dropdown-toggle" type="button" id="dropdownGender"
data-bs-toggle="dropdown" aria-expanded="false">
Selecionar Gênero
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownGender">
@if (ViewBag.Genders != null) {
foreach (var gender in (List<GenderModel>)ViewBag.Genders) {
<li>
<div class="form-check ms-2">
<input type="radio" class="form-check-input" name="GenderId"
value="@gender.GenderId"
asp-for="GenderId"/>
<label class="form-check-label" asp-for="GenderId">@gender.Gender</label>
</div>
</li>
}
} else {
<li>
<span class="dropdown-item">Nenhum gênero cadastrado</span>
</li>
}
</ul>
</div>
</div>
<div class="form-group">
<div class="dropdown p-2">
<button class="btn btn-light dropdown-toggle" type="button" id="dropdownCategories"
data-bs-toggle="dropdown" aria-expanded="false">
Selecionar Categorias
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownCategories">
@if (ViewBag.Categories != null) {
foreach (var category in (List<CategoryModel>)ViewBag.Categories) {
<li>
<div class="form-check ms-2">
<input type="checkbox" class="form-check-input" name="SelectedCategories"
value="@category.CategoryId"/>
<label class="form-check-label">@category.Category</label>
</div>
</li>
}
} else {
<li>
<span class="dropdown-item">Nenhuma categoria cadastrada</span>
</li>
}
<li>
<a role="button" class="btn" asp-controller="Category" asp-action="Register">cadastrar</a>
</li>
</ul>
</div>
</div>
<div class="form-group">
<div class="dropdown p-2">
<button class="btn btn-light dropdown-toggle" type="button" id="dropdownColors"
data-bs-toggle="dropdown" aria-expanded="false">
Selecionar Cores
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownColors">
@if (ViewBag.Colors != null) {
foreach (var color in (List<ColorModel>)ViewBag.Colors) {
<li>
<div class="form-check ms-2">
<input type="checkbox" class="form-check-input" name="SelectedColors"
value="@color.ColorId"/>
<label class="form-check-label">
<div class="color-box color-s"
style="background-color: @color.HexColor"></div>
@color.Color
</label>
</div>
</li>
}
} else {
<li>
<span class="dropdown-item">Nenhuma cor cadastrada</span>
</li>
}
<li>
<a role="button" class="btn" asp-controller="Color" asp-action="Register">cadastrar</a>
</li>
</ul>
</div>
</div>
<div class="form-group">
<div class="dropdown p-2">
<button class="btn btn-light dropdown-toggle" type="button" id="dropdownSizes"
data-bs-toggle="dropdown" aria-expanded="false">
Selecionar Tamanhos
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownSizes">
@if (ViewBag.Sizes != null) {
foreach (var size in (List<SizeModel>)ViewBag.Sizes) {
<li>
<div class="form-check ms-2">
<input type="checkbox" class="form-check-input" name="SelectedSizes"
value="@size.SizeId"/>
<label class="form-check-label">@size.Size</label>
</div>
</li>
}
} else {
<li>
<span class="dropdown-item">Nenhum tamanho cadastrado</span>
</li>
}
<li>
<a role="button" class="btn" asp-controller="Size" asp-action="Register">cadastrar</a>
</li>
</ul>
</div>
</div>
<div class="form-group">
<div id="stockInputsContainer">
</div>
</div>
<div class="form-group">
<a role="button" class="btn btn-secondary" asp-controller="Product" asp-action="Index">Cancelar</a>
<button type="submit" class="btn btn-primary">Enviar</button>
</div>
</form>
</div>
ProductController.cs:
using System.Net.Http.Headers;
using System.Text.Json;
using DLyah_Boutique_System.Models;
using DLyah_Boutique_System.Repository;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Hosting;
namespace DLyah_Boutique_System.Controllers;
public class ProductController : Controller {
private readonly IProductRepository _productRepository;
private readonly IGenderRepository _genderRepository;
private readonly ICategoryRepository _categoryRepository;
private readonly IColorRepository _colorRepository;
private readonly ISizeRepository _sizeRepository;
private readonly IWebHostEnvironment _environment;
private readonly ILogger<ProductController> _logger;
private readonly string _pathImage;
public ProductController(
IProductRepository productRepository, IGenderRepository genderRepository,
ICategoryRepository categoryRepository, IColorRepository colorRepository, ISizeRepository sizeRepository,
IWebHostEnvironment environment, IFileUploadService fileUploadService, ILogger<ProductController> logger
) {
_productRepository = productRepository;
_genderRepository = genderRepository;
_categoryRepository = categoryRepository;
_colorRepository = colorRepository;
_sizeRepository = sizeRepository;
_environment = environment;
_logger = logger;
_pathImage = Path.Combine(_environment.WebRootPath, "images", "products");
}
// GET
public IActionResult Index() {
return View();
}
public IActionResult Register() {
List<GenderModel> genders = _genderRepository.FindAll();
List<CategoryModel> categories = _categoryRepository.FindAll();
List<ColorModel> colors = _colorRepository.FindAll();
List<SizeModel> sizes = _sizeRepository.FindAll();
ViewBag.Genders = genders;
ViewBag.Categories = categories;
ViewBag.Colors = colors;
ViewBag.Sizes = sizes;
return View();
}
[HttpPost]
public async Task<IActionResult> Register(
List<IFormFile> pi, ProductModel product, int genderId, List<int> ct, List<int> c, List<int> s, List<StockProductModel> stck
) {
Console.WriteLine("Register método iniciado");
if (ModelState.IsValid) {
Console.WriteLine("ModelState é válido");
// Adicionar o produto e salvar para obter o ProductId
product.GenderId = genderId;
_productRepository.Create(product);
await _productRepository.SaveChanges();
Console.WriteLine($"Produto adicionado com ID: {product.ProductId}");
if (pi != null && pi.Any()) {
Console.WriteLine($"{pi.Count} imagens recebidas.");
string uploadDir = Path.Combine(_environment.WebRootPath, "images", "products");
Console.WriteLine($"Diretório de upload: {uploadDir}");
if (!Directory.Exists(uploadDir)) {
Console.WriteLine($"Diretório não existe, criando: {uploadDir}");
Directory.CreateDirectory(uploadDir);
}
int order = 1;
foreach (var imageFile in pi) {
if (imageFile.Length > 0) {
Console.WriteLine($"Processando imagem: {imageFile.FileName}, Tamanho: {imageFile.Length}");
try {
string imageName = $"{product.ProductName.Replace(" ", "-")}-{Guid.NewGuid().ToString().Substring(0, 8)}{Path.GetExtension(imageFile.FileName)}";
string filePath = Path.Combine(uploadDir, imageName);
using (var stream = new FileStream(filePath, FileMode.Create)) {
await imageFile.CopyToAsync(stream);
Console.WriteLine($"[DEBUG] Imagem salva em: {filePath}");
}
_productRepository.CreateProductImage(new ProductImageModel {
ProductId = product.ProductId,
ProductImagePath = $"/images/products/{imageName}",
ImageOrder = order++
});
} catch (Exception ex) {
Console.WriteLine($"[ERROR] Erro ao salvar a imagem {imageFile.FileName}: {ex.Message}");
ModelState.AddModelError("pi", $"Ocorreu um erro ao salvar a imagem {imageFile.FileName}.");
}
}
}
await _productRepository.SaveChanges();
Console.WriteLine("Imagens salvas.");
}
if (ct != null && ct.Any()) {
foreach (var categoryId in ct) {
_productRepository.CreateProductCategory(product.ProductId, categoryId);
}
}
if (c != null && c.Any()) {
foreach (var colorId in c) {
_productRepository.CreateProductColor(product.ProductId, colorId);
}
}
if (s != null && s.Any()) {
foreach (var sizeId in s) {
_productRepository.CreateProductSize(product.ProductId, sizeId);
}
}
if (stck != null && stck.Any()) {
foreach (var stockItem in stck) {
stockItem.ProductId = product.ProductId; // Garante que o ProductId esteja definido
_productRepository.CreateStockProduct(stockItem);
}
await _productRepository.SaveChanges();
}
await _productRepository.SaveChanges();
return RedirectToAction("Index");
} else {
Console.WriteLine("ModelState não é válido");
foreach (var error in ModelState.Values.SelectMany(v => v.Errors)) {
Console.WriteLine($"Erro: {error.ErrorMessage}");
}
}
// Se o modelo não for válido, retornar à view com os dados do produto
List<GenderModel> genders = _genderRepository.FindAll();
List<CategoryModel> categories = _categoryRepository.FindAll();
List<ColorModel> colors = _colorRepository.FindAll();
List<SizeModel> sizes = _sizeRepository.FindAll();
ViewBag.Genders = genders;
ViewBag.Categories = categories;
ViewBag.Colors = colors;
ViewBag.Sizes = sizes;
return View(product);
}
}
ProductRepository.cs:
using DLyah_Boutique_System.Data;
using DLyah_Boutique_System.Models;
using Microsoft.EntityFrameworkCore;
namespace DLyah_Boutique_System.Repository;
public class ProductRepository : IProductRepository {
private readonly BankContext _context;
public ProductRepository(BankContext context) {
_context = context;
}
public List<ProductModel> FindAll() {
return _context.Products
.Include(pg => pg.Gender)
.Include(p => p.ProductCategories)
.ThenInclude(pc => pc.Category)
.Include(p => p.ProductColors)
.ThenInclude(pc => pc.Color)
.Include(p => p.ProductSizes)
.ThenInclude(ps => ps.Size)
.Include(p => p.ProductImages.OrderBy(pi => pi.ImageOrder))
.Include(pstck => pstck.StockProducts)
.ToList();
}
public ProductModel? FindById(int id) {
return _context.Products
.Include(pg => pg.Gender)
.Include(p => p.ProductCategories)
.ThenInclude(pc => pc.Category)
.Include(p => p.ProductColors)
.ThenInclude(pc => pc.Color)
.Include(p => p.ProductSizes)
.ThenInclude(ps => ps.Size)
.Include(p => p.ProductImages.OrderBy(pi => pi.ImageOrder))
.Include(p => p.StockProducts) // Inclui os itens de estoque
.FirstOrDefault(p => p.ProductId == id);
}
public ProductModel Update(ProductModel product) {
ProductModel productDb = FindById(product.ProductId);
if (productDb == null) throw new Exception("Houve um erro ao atualizar o produto");
productDb.ProductName = product.ProductName;
productDb.ProductDescription = product.ProductDescription;
productDb.ProductPrice = product.ProductPrice;
productDb.GenderId = product.GenderId;
productDb.ProductColors.Clear();
if (product.ProductColors != null) {
foreach (var pc in product.ProductColors) {
productDb.ProductColors.Add(new ProductColorModel
{ ProductId = product.ProductId, ColorId = pc.ColorId });
}
}
// Atualizar ProductSizes
productDb.ProductSizes.Clear();
if (product.ProductSizes != null) {
foreach (var ps in product.ProductSizes) {
productDb.ProductSizes.Add(new ProductSizeModel { ProductId = product.ProductId, SizeId = ps.SizeId });
}
}
// Atualizar ProductCategories
productDb.ProductCategories.Clear();
if (product.ProductCategories != null) {
foreach (var pc in product.ProductCategories) {
productDb.ProductCategories.Add(new ProductCategoryModel
{ ProductId = product.ProductId, CategoryId = pc.CategoryId });
}
}
// Atualizar ProductImages (requer mais lógica dependendo de como você gerencia as imagens - adicionar, remover, etc.)
// Este é um exemplo básico que remove todas as existentes e adiciona as novas
productDb.ProductImages.Clear();
if (product.ProductImages != null) {
foreach (var pi in product.ProductImages) {
productDb.ProductImages.Add(new ProductImageModel {
ProductId = product.ProductId, ProductImagePath = pi.ProductImagePath, ImageOrder = pi.ImageOrder
});
}
}
_context.Products.Update(productDb);
_context.SaveChanges();
return productDb;
}
public ProductModel Create(ProductModel product) {
_context.Products.Add(product);
_context.SaveChanges();
return product;
}
public ProductCategoryModel CreateProductCategory(int productId, int categoryId) {
ProductCategoryModel productCategory = new ProductCategoryModel {
ProductId = productId,
CategoryId = categoryId
};
_context.ProductCategories.Add(productCategory);
return productCategory;
}
public ProductColorModel CreateProductColor(int productId, int colorId) {
ProductColorModel productColor = new ProductColorModel {
ProductId = productId,
ColorId = colorId
};
_context.ProductColors.Add(productColor);
return productColor;
}
public ProductSizeModel CreateProductSize(int productId, int sizeId) {
ProductSizeModel productSize = new ProductSizeModel {
ProductId = productId,
SizeId = sizeId
};
_context.ProductSizes.Add(productSize);
return productSize;
}
public ProductImageModel CreateProductImage(ProductImageModel productImage) {
_context.ProductImages.Add(productImage);
return productImage;
}
public StockProductModel CreateStockProduct(StockProductModel stock) {
_context.StockProducts.Add(stock);
return stock;
}
public ProductModel Kill(ProductModel product) {
throw new NotImplementedException();
}
public Task<int> SaveChanges() {
return _context.SaveChangesAsync();
}
}