Having started studying asp net core 6, I ran into the problem of invalidity of my model. What is the hidden problem?
Model of Product
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace TestWebApplication.Models
{
public class Product
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
[Range(0.1, int.MaxValue)]
public double Price { get; set; }
public string Image { get; set; }
[Display(Name = "Category Type")]
public int CategoryId { get; set; }
[ForeignKey("CategoryId")]
public virtual Category Category { get; set; }
}
}
Model of ProductVM
using Microsoft.AspNetCore.Mvc.Rendering;
namespace TestWebApplication.Models.ViewModels
{
public class ProductVM
{
public Product Product { get; set; }
public IEnumerable<SelectListItem> CategorySelectList { get; set; }
}
}
View
@model TestWebApplication.Models.ViewModels.ProductVM
@{
var title = "Create Product";
}
<form method="post" enctype="multipart/form-data">
@if(Model.Product.Id != 0)
{
title = "Edit Product";
<input asp-for="Product.Id" hidden />
}
<div >
<div >
<h2 >@title</h2>
</div>
<br />
<div >
<div >
<div >
<div >
<label asp-for="Product.Name"></label>
</div>
<div >
<input asp-for="Product.Name" />
<span asp-validation-for="Product.Name" ></span>
</div>
</div>
<br />
<div >
<div >
<label asp-for="Product.Price"></label>
</div>
<div >
<input asp-for="Product.Price" />
<span asp-validation-for="Product.Price" ></span>
</div>
</div>
<br />
<div >
<div >
<label asp-for="Product.Description"></label>
</div>
<div >
<textarea asp-for="Product.Description" > </textarea>
<span asp-validation-for="Product.Description" ></span>
</div>
</div>
<br />
<div >
<div >
Image
</div>
<div >
<input type = "file" name="files" id="uploadBox" multiple />
</div>
</div>
<br />
<div >
<div >
<label asp-for="Product.CategoryId"></label>
</div>
<div >
<select asp-for="Product.CategoryId" asp-items="@Model.CategorySelectList" >
<option disabled selected>---Select Category---</option>
</select>
<span asp-validation-for="Product.CategoryId" ></span>
</div>
</div>
<br />
<div >
<div >
<div >
@if (Model.Product.Id != 0)
{
//update
<input type="submit" value="Update"/>
}
else
{
//create
<input type="submit" onclick="return validateInput()" value="Create"/>
}
</div>
<div >
<a asp-action="Index" >
Back
</a>
</div>
</div>
</div>
</div>
<div >
@* Keep this empty *@
</div>
</div>
</div>
</form>
@section Scripts
{
@{
<partial name= "_ValidationScriptsPartial.cshtml"/>
}
<script>
$(document).ready(function() {
$('.summernote').summernote(
{
height:250
});
});
function validateInput()
{
if (document.getElementById("uploadBox").value == "")
{
Swal.fire
(
'Error!',
'Please, upload an image',
'error'
)
return false;
}
return true;
}
</script>
}
Controller
using TestWebApplication.Data;
using TestWebApplication.Models;
using TestWebApplication.Models.ViewModels;
namespace TestWebApplication.Controllers
{
public class ProductController : Controller
{
private readonly ApplicationDbContext _db;
private readonly IWebHostEnvironment _webHostEnvironment;
public ProductController(ApplicationDbContext db, IWebHostEnvironment webHostEnvironment)
{
_db = db;
_webHostEnvironment = webHostEnvironment;
}
public IActionResult Index()
{
IEnumerable<Product> objList = _db.Product;
foreach (var item in objList)
{
item.Category = _db.Category.FirstOrDefault(category => category.Id == item.Id);
}
return View(objList);
}
// get - upsert
public IActionResult Upsert(int? id)
{
//IEnumerable<SelectListItem> CategoryDropDown = _db.Category.Select(i => new SelectListItem
//{
// Text = i.Name,
// Value = i.Id.ToString()
//});
//ViewBag.CategoryDropDown = CategoryDropDown;
//Product product = new Product();
ProductVM productVM = new ProductVM()
{
Product = new Product(),
CategorySelectList = _db.Category.Select(i => new SelectListItem
{
Text = i.Name,
Value = i.Id.ToString()
})
};
if(id == null)
{
// for create
return View(productVM);
}
else
{
productVM.Product = _db.Product.Find(id);
if (productVM.Product == null)
NotFound();
return View(productVM);
}
}
// post - upsert
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Upsert(ProductVM obj)
{
if (ModelState.IsValid)
{
var files = HttpContext.Request.Form.Files;
string webRootPath = _webHostEnvironment.WebRootPath;
if(obj.Product.Id == 0)
{
//Creating
string upload = webRootPath WC.ImagePath;
string fileName = Guid.NewGuid().ToString();
string extention = Path.GetExtension(files[0].FileName);
using(var fileStream = new FileStream(Path.Combine(upload, fileName extention), FileMode.Create))
{
files[0].CopyTo(fileStream);
}
obj.Product.Image = fileName extention;
_db.Product.Add(obj.Product);
}
else
{
//Updating
}
return RedirectToAction("Index");
}
return View();
}
}
List of fields that participated in validation
From one answer, I realized that the Category field will remain null, and ef core will substitute the values. But I don't quite understand why so many fields are validated without being marked required in the model.
CodePudding user response:
By receives a POST action, ModelState takes all of the name-value pairs and adds them as individual instances of ModelStateEntry to an instance of ModelStateDictionary. ModelState checks all properties regardless of whether they have a Data annotations or not, such as you get a number, text, file etc. But for those data annotations you put on the properties the ModelState makes a special check based on it.
CodePudding user response:
Just the properties of the model you passed to controller would be validated,you could try custom model validation follow this document:
And you could try with ModelState.AddModelError(string.Empty, "errormessage");
add model level error in backend.