How to get DropDownList SelectedValue to update Database - asp.net-core-mvc

I finally was able to get cascading drowdownlist working but I can not get the values to update the database table.
Controller
public IActionResult Create()
{
var strRowWid = "RowWid";
var strDt = "Dt";
var dateNow = DateOnly.FromDateTime(DateTime.Now);
//Date Dropdown
ViewBag.DateWid = new SelectList(_context.TblDays.OrderByDescending(x => x.Dt).Where(n => n.Dt <= dateNow), strRowWid, strDt);
//Ammo Type dropdown
ViewBag.ammo = _context.VwAmmos.OrderBy(n => n.Caliber)
.Select(n => new SelectListItem
{
Value = n.RowWid.ToString(),
Text = n.WeaponType.ToString() + " " + n.Caliber.ToString() + " " + n.Brand.ToString() + " " + n.Style.ToString(),
}).ToList();
return View();
}
HTML
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
#Html.LabelFor(model => model.TblUsed.DateWid, htmlAttributes: new { #class = "control-label"})
<div>
#Html.DropDownList("DateWid", ViewBag.DateWid as SelectList, "--select date--", new { #class = "form-control form-select-sm form-select" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TblUsed.AmmoWid, htmlAttributes: new { #class = "control-label"})
<div>
#Html.DropDownList("AmmoWid",ViewBag.ammo, "--select Ammo--", new { #class = "form-control form-select-sm form-select" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TblUsed.StoreWid, htmlAttributes: new { #class = "control-label"})
<div>
#Html.DropDownList("StoreWid",new SelectList(string.Empty,"StoreWid","StoreName"), new { #class = "form-control form-select-sm form-select" })
</div>
</div>
<div class="form-group">
<label asp-for="#Model.TblUsed.QtyUsed" class="control-label"></label>
<input asp-for="#Model.TblUsed.QtyUsed" class="form-control" />
<span asp-validation-for="#Model.TblUsed.QtyUsed" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
Javascript for the cascade
<script>
$('#AmmoWid').change(function () {
$('#StoreWid').empty();
$.ajax({
url: "#Url.Action("GetStore")",
type: "Get",
data: { id: $('#AmmoWid option:selected').val() },
dataType:"json",
success: function (result) {
$.each(result, function (i,Store) {
$('#StoreWid').append('<option value="' + Store.value + '">' + Store.text+'</option>')
})
}
})
})
</script>
When I select the values from the dropdownlist and submit they do not update the database table. It appears that they are not binded correctly.
I don't know what to try at this point.
When doing them like this I can get them to update but then I can't do the cascading.
<div class="form-group col-2">
<select asp-for="#Model.TblPurchase.AmmoWid" class="form-control form-select-sm form-select" asp-items="#Model.Ammo">
<option value="">Select Ammo</option>
</select>
<span asp-validation-for="#Model.TblPurchase.AmmoWid" class="text-danger"></span>
</div>
Create Post
// POST: Useds/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("RowWid,DateWid,AmmoWid,QtyUsed,StoreWid")] TblUsed tblUsed)
{
if (ModelState.IsValid)
{
_context.Add(tblUsed);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(tblUsed);
}
TblUsed Model
namespace Ammo.Models;
public partial class TblUsed
{
[Key]
public int RowWid { get; set; }
[ForeignKey("TblDay")]
[DisplayName("Date")]
public int DateWid { get; set; }
[ForeignKey("TblAmmunition")]
[DisplayName("Ammo")]
public int AmmoWid { get; set; }
public int QtyUsed { get; set; }
[ForeignKey("TblStore")]
[DisplayName("Store")]
public int StoreWid { get; set; }
}
VwAmmo Model
namespace Ammo.Models;
public partial class VwAmmo
{
public int RowWid { get; set; }
public string? WeaponType { get; set; }
public string? Caliber { get; set; }
public string Brand { get; set; } = null!;
public string Style { get; set; } = null!;
public int? Grain { get; set; }
public int? FtS { get; set; }
public decimal? ShellSize { get; set; }
public string? ShotType { get; set; }
public string? Shot { get; set; }
public decimal? GrainLoad { get; set; }
}

The reason why you couldn't get the tblUsed value is you used the wrong name for your attribute.
I suggest you could try to modify as below and then test. Besides, there is no need to put the bind attribute again.
View codes:
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
#Html.LabelFor(model => model.TblUsed.DateWid, htmlAttributes: new { #class = "control-label"})
<div>
#Html.DropDownList("TblUsed.DateWid", ViewBag.DateWid , "--select date--", new { #class = "form-control form-select-sm form-select" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TblUsed.AmmoWid, htmlAttributes: new { #class = "control-label"})
<div>
#Html.DropDownList("TblUsed.AmmoWid",ViewBag.ammo, "--select Ammo--", new { #class = "form-control form-select-sm form-select" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TblUsed.StoreWid, htmlAttributes: new { #class = "control-label"})
<div>
#Html.DropDownList("TblUsed.StoreWid",new SelectList(string.Empty,"StoreWid","StoreName"), new { #class = "form-control form-select-sm form-select" })
</div>
</div>
<div class="form-group">
<label asp-for="#Model.TblUsed.QtyUsed" class="control-label"></label>
<input asp-for="#Model.TblUsed.QtyUsed" class="form-control" />
<span asp-validation-for="#Model.TblUsed.QtyUsed" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
#section Scripts{
<script>
$('#TblUsed_AmmoWid').change(function () {
$('#TblUsed_StoreWid').empty();
$.ajax({
url: "#Url.Action("GetStore")",
type: "Get",
data: { id: $('#TblUsed_AmmoWid option:selected').val() },
dataType:"json",
success: function (result) {
$.each(result, function (i,Store) {
$('#TblUsed_StoreWid').append('<option value="' + Store.value + '">' + Store.text+'</option>')
})
}
})
})
</script>
}

Related

Edit method in ASP.NET Core 6 MVC

I am building an e-store web app using ASP.NET Core 6 MVC. I am trying to do CRUD operations with the help of some tutorial, everything went smoothly, but when I try to edit a product, it makes a copy of that edited item, instead of just replacing it.
Also, it asks me to upload a new image even though I want to set it not to ask for a new one, and there is a default (noimage.png) set if there is no image uploaded. Here is the edit method, please tell me where am going wrong.
public async Task<IActionResult> Edit(int id, Product product)
{
ViewBag.CategoryId = new SelectList(_context.Category.OrderBy(x => x.Sorting),
"Id", "Name", product.CategoryId);
// if (ModelState.IsValid)
// {
product.Slug = product.Name.ToLower().Replace(" ", "-");
var slug = await _context.Product
.Where(x => x.Id != id)
.FirstOrDefaultAsync(x => x.Slug == product.Slug);
if (slug != null)
{
ModelState.AddModelError("", "The product already exists.");
return View(product);
}
// Not mandatory to upload an image when editing
if (product.ImageUpload != null)
{
string uploadsDir = Path.Combine(webHost.WebRootPath, "media/products");
// If the image is not noimage.png then remove the existing image and upload a new one
if (!string.Equals(product.Image, "noimage.png"))
{
string oldImagePath = Path.Combine(uploadsDir, product.Image);
if (System.IO.File.Exists(oldImagePath))
{
System.IO.File.Delete(oldImagePath);
}
}
// Upload new image
string imageName = Guid.NewGuid().ToString() + "_" + product.ImageUpload.FileName;
string filePath = Path.Combine(uploadsDir, imageName);
FileStream fs = new FileStream(filePath, FileMode.Create);
await product.ImageUpload.CopyToAsync(fs);
fs.Close();
product.Image = imageName;
}
_context.Update(product);
await _context.SaveChangesAsync();
TempData["Success"] = "The product has been edited!";
return RedirectToAction("Index");
// }
// return View(product);
}
Product class
public class Product
{
public int Id { get; set; }
[Required, MinLength(2, ErrorMessage = "Minimum length 2")]
public string? Name { get; set; }
public string? Slug { get; set; }
[Column(TypeName = "decimal (18,2)")]
public decimal Price { get; set; }
[Display(Name = "Category")]
[Range(1, int.MaxValue, ErrorMessage = "You must choose a category")] //specific validation for category
public int? CategoryId { get; set; }
[Required, MinLength(2, ErrorMessage = "Minimum length 4")]
public string? Description { get; set; }
public string? Image { get; set; }
//To make the connection
[ForeignKey("CategoryId")]
public virtual Category? Category { get; set; }
[NotMapped] //to not show in the DB
[ImageExtention]
public IFormFile? ImageUpload { get; set; }
}
Edit view
#model Product
#{
ViewData["Title"] = "Edit Product";
}
<h1>Edit Product</h1>
<div class="row">
<div class="col-md-10">
<form asp-action="Edit" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#*<input type="hidden" asp-for="Image" />*#
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<textarea asp-for="Description" class="form-control"></textarea>
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CategoryId" class="control-label"></label>
<select asp-for="CategoryId" asp-items="#ViewBag.CategoryId" class="form-control">
<option value="0">Choose a category</option>
</select>
<span asp-validation-for="CategoryId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Image" class="control-label">Current Image</label>
<img src="~/media/products/#Model.Image" width="200" alt="" />
</div>
<div class="form-group">
<label asp-for="Image" class="control-label">New Product Image</label>
<input asp-for="ImageUpload" class="form-control" />
<img src="" id="imgpreview" class="pt-2" alt="" />
<span asp-validation-for="ImageUpload" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Edit" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
<script>
$("#ImageUpload").change(function () {
readURL(this);
});
</script>
}
You need to make Id as Primary Key in Product
public class Product
{
[Key]
public int Id { get; set; }
//ommitted
}
You are not posting Id to Edit Method while Edit button clicked. So every time It is sending value of Id as 0. EntityFramework is considering it as new object.
Please add below code to cshtml view inside form. It will send correct value of existing product Id.
<input type="hidden" asp-for="Id" />

Getting a DropDown SelectList working in MVC Core using a ViewModel and Entity Framework

I have been trying to create an application with the CodeFirst approach with MVC Core and using the Entity Framework and a ViewModel.
The issue is that nothing populates in the branch dropdown.
For the life of me I cannot figure out what I am doing wrong, but I suspect that the problem in my controller.
Please help.
My Models
public class Intermediary
{
public int IntermediaryID {get; set; }
public string RegisteredName {get; set; }
public string TradingName {get; set; }
public DateTime CreatedDate{get; set; }
public stringCreatedBy {get; set; }
}
public class Branch
{
public int BranchID {get; set; }
public string Name {get; set; }
public DateTime CreatedDate{get; set; }
public stringCreatedBy {get; set; }
}
My ViewModel
public class IntermediaryIndexData
{
public IEnumerable<Intermediary> Intermediaries { get; set; }
public IEnumerable<Branch> Branches { get; set; }
}
My Controller
namespace BizDevHub.Controllers
{
public class IntermediariesController : Controller
{
private readonly BizDevHubContext _context;
public IntermediariesController(BizDevHubContext context)
{
_context = context;
}
// GET: Intermediaries
public async Task<IActionResult> Index(int? id, int? intermediaryID)
{
var viewModel = new IntermediaryIndexData();
viewModel.Intermediaries = await _context.Intermediaries
.Include(i => i.Branch)
.AsNoTracking()
.OrderBy(i => i.RegisteredName)
.ToListAsync();
//if (id != null)
//{
// ViewData["IntermdiaryID"] = id.Value;
// Instructor instructor = viewModel.Instructors.Where(
// i => i.ID == id.Value).Single();
// viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
//}
//if (courseID != null)
//{
// ViewData["CourseID"] = courseID.Value;
// viewModel.Enrollments = viewModel.Courses.Where(
// x => x.CourseID == courseID).Single().Enrollments;
//}
return View(viewModel);
}
// GET: Intermediaries/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var intermediary = await _context.Intermediaries
.Include(c => c.Branch)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.IntermediaryID == id);
if (intermediary == null)
{
return NotFound();
}
return View(intermediary);
}
// GET: Intermediaries/Create
public IActionResult Create()
{
PopulateBranchesDropDownList();
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("IntermediaryID,RegisteredName,TradingName,Registration,VATNumber,FSPNumber,CreatedDate,CreatedBy,BranchID,AgreementID")] Intermediary intermediary)
{
if (ModelState.IsValid)
{
_context.Add(intermediary);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
PopulateBranchesDropDownList(intermediary.BranchID);
return View(intermediary);
}
// GET: Intermediaries/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var intermediary = await _context.Intermediaries
.AsNoTracking()
.FirstOrDefaultAsync(m => m.IntermediaryID == id);
if (intermediary == null)
{
return NotFound();
}
PopulateBranchesDropDownList(intermediary.BranchID);
return View(intermediary);
}
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditPost(int? id)
{
if (id == null)
{
return NotFound();
}
var intermediaryToUpdate = await _context.Intermediaries
.FirstOrDefaultAsync(c => c.IntermediaryID == id);
if (await TryUpdateModelAsync<Intermediary>(intermediaryToUpdate,
"",
c => c.RegisteredName,
c => c.TradingName,
c => c.Registration,
c => c.VATNumber,
c => c.FSPNumber,
c => c.CreatedBy,
c => c.CreatedDate,
c => c.BranchID,
c => c.AgreementID
))
{
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
ModelState.AddModelError("", "Unable to save changes. " + "Try again, and if the problem persists, " + "see your system administrator.");
}
return RedirectToAction(nameof(Index));
}
PopulateBranchesDropDownList(intermediaryToUpdate.BranchID);
ViewData["BranchID"] = new SelectList(_context.Branches, "BranchID", "Name", intermediaryToUpdate.BranchID);
return View(intermediaryToUpdate);
}
// GET: Intermediaries/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var intermediary = await _context.Intermediaries
.Include(c => c.Branch)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.IntermediaryID == id);
if (intermediary == null)
{
return NotFound();
}
return View(intermediary);
}
// POST: Intermediaries/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var intermediary = await _context.Intermediaries.FindAsync(id);
_context.Intermediaries.Remove(intermediary);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool IntermediaryExists(int id)
{
return _context.Intermediaries.Any(e => e.IntermediaryID == id);
}
private void PopulateBranchesDropDownList(object selectedBranch = null)
{
var branchesQuery = from d in _context.Branches
orderby d.Name
select d;
ViewBag.DepartmentID = new SelectList(branchesQuery.AsNoTracking(), "BranchID", "Name", selectedBranch);
}
}
}
My Views
I added the views using scaffolding
Index
#model BizDevHub.Models.ViewModels.IntermediaryIndexData
#{
ViewData["Title"] = "Intermediaries";
}
<h2>Intermediary</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>Registered Name</th>
<th>Trading As</th>
<th>Created Date</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Intermediaries)
{
string selectedRow = "";
if (item.IntermediaryID == (int?)ViewData["IntermediaryID"])
{
selectedRow = "success";
}
<tr class="#selectedRow">
<td>
#Html.DisplayFor(modelItem => item.RegisteredName)
</td>
<td>
#Html.DisplayFor(modelItem => item.TradingName)
</td>
<td>
#Html.DisplayFor(modelItem => item.FSPNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.Registration)
</td>
<td>
#Html.DisplayFor(modelItem => item.VATNumber)
</td>
<th>
#Html.DisplayNameFor(model => item.Branch)
</th>
<td>
<a asp-action="Edit" asp-route-id="#item.IntermediaryID">Edit</a> |
<a asp-action="Details" asp-route-id="#item.IntermediaryID">Details</a> |
<a asp-action="Delete" asp-route-id="#item.IntermediaryID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Edit
#model BizDevHub.Models.Intermediary
#{
ViewData["Title"] = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
<h4>Intermediary</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="IntermediaryID" />
<div class="form-group">
<label asp-for="RegisteredName" class="control-label"></label>
<input asp-for="RegisteredName" class="form-control" />
<span asp-validation-for="RegisteredName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="TradingName" class="control-label"></label>
<input asp-for="TradingName" class="form-control" />
<span asp-validation-for="TradingName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Registration" class="control-label"></label>
<input asp-for="Registration" class="form-control" />
<span asp-validation-for="Registration" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="VATNumber" class="control-label"></label>
<input asp-for="VATNumber" class="form-control" />
<span asp-validation-for="VATNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FSPNumber" class="control-label"></label>
<input asp-for="FSPNumber" class="form-control" />
<span asp-validation-for="FSPNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedDate" class="control-label"></label>
<input asp-for="CreatedDate" class="form-control" />
<span asp-validation-for="CreatedDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedBy" class="control-label"></label>
<input asp-for="CreatedBy" class="form-control" />
<span asp-validation-for="CreatedBy" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Branch" class="control-label"></label>
<select asp-for="BranchID" class="form-control" asp-items="ViewBag.BranchID">
<option value=""></option>
</select>
<span asp-validation-for="BranchID" class="text-danger" />
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
#model BizDevHub.Models.Intermediary
Create
#model BizDevHub.Models.Intermediary
#{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
<h4>Intermediary</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="RegisteredName" class="control-label"></label>
<input asp-for="RegisteredName" class="form-control" />
<span asp-validation-for="RegisteredName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="TradingName" class="control-label"></label>
<input asp-for="TradingName" class="form-control" />
<span asp-validation-for="TradingName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Registration" class="control-label"></label>
<input asp-for="Registration" class="form-control" />
<span asp-validation-for="Registration" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="VATNumber" class="control-label"></label>
<input asp-for="VATNumber" class="form-control" />
<span asp-validation-for="VATNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FSPNumber" class="control-label"></label>
<input asp-for="FSPNumber" class="form-control" />
<span asp-validation-for="FSPNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedBy" class="control-label"></label>
<input asp-for="CreatedBy" class="form-control" />
<span asp-validation-for="CreatedBy" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Branches" class="control-label"></label>
<select asp-for="BranchID" class="form-control" asp-items="ViewBag.BranchID">
<option value="">-- Select Branch --</option>
</select>
<span asp-validation-for="BranchID" class="text-danger" />
</div>
#*<div class="form-group">
<label asp-for="AgreementID" class="control-label"></label>
<input asp-for="AgreementID" class="form-control" />
<span asp-validation-for="AgreementID" class="text-danger"></span>
</div>*#
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
For the life of me I cannot figure out what I am doing wrong, but I suspect that the problem in my controller.
Please help.
It seems that there is a one-to-many relationship between Branch and Intermediary , so your model design should be like below:
public class Intermediary
{
public int IntermediaryID { get; set; }
public string RegisteredName { get; set; }
public string TradingName { get; set; }
public DateTime CreatedDate { get; set; }
public string CreatedBy {get; set; }
public int BranchID { get; set; }
public Branch Branch { get; set; }
}
public class Branch
{
public int BranchID { get; set; }
public string Name { get; set; }
public DateTime CreatedDate { get; set; }
public string CreatedBy {get; set; }
public List<Intermediary> Intermediaries { get; set; }
}
->>The issue is that nothing populates in the branch dropdown.
The key-name of ViewBagb in the view and the controller are inconsistent, you should change PopulateBranchesDropDownList method
private void PopulateBranchesDropDownList(object selectedBranch = null)
{
var branchesQuery = from d in _context.Branches
orderby d.Name
select d;
ViewBag.BranchID= new SelectList(branchesQuery.AsNoTracking(), "BranchID", "Name", selectedBranch);
}
You could refer to here for more details about relationships in EF Core.

How to data list to model and model's data send with one post process from view to controller?

My model(dto);
public class DTOExample
{
#region Properties
[Required(ErrorMessage = "Required")]
[DataType(DataType.Text)]
[Display(Name = "Name")]
public string Name{ get; set; }
[Required(ErrorMessage = "Required")]
[StringLength(12, ErrorMessage = "{0} alanı en az {1}, en çok {2} karakter olabilir.", MinimumLength = 12)]
[DataType(DataType.Text)]
[Display(Name = "Last Name")]
public string LastName{ get; set; }
[Display(Name = "Send Information")]
public List<DTOSendInformations> ListSend { get; set; }
}
public class DTOSendInformations
{
[Display(Name = "AdressOne")]
[Required(ErrorMessage = "Zorunlu alan")]
[StringLength(50, ErrorMessage = "{0} min {2}, max {1}", MinimumLength = 1)]
[DataType(DataType.Text)]
public string AdressOne{ get; set; }
[Display(Name = "AdressTwo")]
[StringLength(11, ErrorMessage = "{0} min {2}, max {1} karakter olabilir.", MinimumLength = 10)]
[DataType(DataType.Text)]
public string AdressTwo{ get; set; }
}
My View (I have written the necessary parts)
<div class="row">
<div class="col-md-6">
<div class="row">
<div class="col-md-4">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<div class="col-md-4">
#Html.LabelFor(model => model.LastName, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.EditorFor(model => model.LastName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ParcaliAlisIzinGostergesi, "", new { #class = "text-danger" })
</div>
</div>
</div>
</div><br />
//I have a table,for AdressOne and AdressTwo,I can enter data dynamically int he view
<table id="tableSendInformation" class="table" cellpadding="0" cellspacing="0">
<thead>
<tr>Send Information Detail</tr>
<tr>
<th style="width:150px">AdressOne</th>
<th style="width:250px">AdressTwo</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
#{
for (int i = 0; i < Model.ListSend.Count; i++)
{
<tr>
<td>
#Html.EditorFor(l => l.ListSend [i].AdressOne)
</td>
<td>
#Html.EditorFor(l => l.ListSend [i].AdressTwo)
</td>
</tr>
}
}
</tfoot>
</table>
//my buttons;
<div class="float-right"> // my button(for AdressOne and AdressTwo)
<div class="col-md-offset-8">
<input type="button" value="Add" class="btn btn-primary" name="Add" id="Add"/>
</div>
</div>
<div class="col-md-offset-8"> //my submit button
<input type="submit" value="Save" id="buttonSave" class="btn btn-primary" name="buttonSave" />
</div>
I want Name,LastName, AdressOne,AdressTwo(multiple records) data, when you click the button(submit buton=>buttonSave) all of this information send from view to controller(I want to submit at the same time).
I want to send both my data and list in the model with a single post.
How can I do that?

Remote validation fails with IFormFile attribute

I notice that remote validation in ASP.NET core always fails because the server always receives a null IFormFile in the controller method. Is there a way to make it work?. Some code to reproduce the problem:
The model class ("not mapped" was included so Entity Framework doesn't interfere, but it also didn't work in another project without Entity Framework.
public class Movie
{
public int ID { get; set; }
[Sacred(sacredWord: "sonda")]
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[Remote(action: "VerifyRating", controller: "Movies")]
public string Rating { get; set; }
[NotMapped]
[Remote(action: "VerifyFile", controller: "Movies"),Required]
public IFormFile File { get; set; }
}
The controller
public class MoviesController : Controller
{
private readonly WebAppMVCContext _context;
public MoviesController(WebAppMVCContext context)
{
_context = context;
}
// GET: Movies/Create
public IActionResult Create()
{
return View();
}
[AcceptVerbs("Get", "Post")]
public IActionResult VerifyFile(IFormFile File)
{
if(File == null)
{
return Json("The file is null");
}
else
{
return Json("The file is not null");
}
}
// POST: Movies/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (ModelState.IsValid)
{
_context.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(movie);
}
[AcceptVerbs("Get", "Post")]
public IActionResult VerifyRating( int rating)
{
if(rating>0 && rating < 10)
{
return Json(true);
}
else
{
return Json($"The rating is invalid");
}
}
and the View
#model WebAppMVC.Models.Movie
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Rating" class="control-label"></label>
<input asp-for="Rating" class="form-control" />
<span asp-validation-for="Rating" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="File" class="control-label"></label>
<input asp-for="File" />
<span asp-validation-for="File" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts{
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script type="text/javascript">
$.validator.addMethod('sacred',
function (value, element, params) {
var title = $(params[0]).val(),
sacredword = params[1];
if (title!=null && title == sacredword) {
return true;
}
else {
return false;
}
}
);
$.validator.unobtrusive.adapters.add('sacred',
['sacredword'],
function (options) {
var element = $(options.form).find('input#Title')[0];
options.rules['sacred'] = [element, options.params['sacredword']];
options.messages['sacred'] = options.message;
}
);
</script>
}
Notice that all the other validations work (including the remote validation "VerifyRating").

Error with expressive annotations requiredif validator

This is my view
<div id="Domain">
<ul class="formlist">
<li class="width100">
<div class="form-check form-check-inline">
<label class="form-check-label">
#Html.RadioButtonFor(model => model.domain_flag, 1, new { #class = "form-check-input" }) <span>Yes</span>
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
#Html.RadioButtonFor(model => model.domain_flag, 0, new { #class = "form-check-input", #checked = "checked" }) <span>No</span>
</label>
</div>
</li>
</ul>
<ul class="formlist">
<li>
<div class="frm-marg-b">
<label class="label"><b>#Html.LabelFor(model => model.domain_renew_date)</b></label>
<div class="textbx">
<div class="input-group">
#Html.TextBoxFor(model => model.domain_renew_date, new { #type = "datetime", #class = "form-control" })
#Html.ValidationMessageFor(model => model.domain_renew_date, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="frm-marg-b">
<label class="label"><b>#Html.LabelFor(model => model.domain_vendor_id)</b></label>
<div class="textbx">
#Html.DropDownListFor(model => model.domain_vendor_id, Model.domain_Vendor, "Please Select")
#Html.ValidationMessageFor(model => model.domain_vendor_id, "", new { #class = "text-danger" })
</div>
</div>
</li>
<li>
<div class="frm-marg-b">
<label class="label"><b>#Html.LabelFor(model => model.domain_exp_date)</b></label>
<div class="textbx">
<div class="input-group">
#Html.TextBoxFor(model => model.domain_exp_date, new { #type = "datetime", #class = "form-control" })
#Html.ValidationMessageFor(model => model.domain_exp_date, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="frm-marg-b">
<label class="label"><b>#Html.LabelFor(model => model.domain_amt)</b></label>
<div class="textbx">
#Html.EditorFor(model => model.domain_amt, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.domain_amt, "", new { #class = "text-danger" })
</div>
</div>
</li>
<li class="width100">
<div class="frm-marg-b">
<label class="label"><b>#Html.LabelFor(model => model.domain_remarks)</b></label>
<div class="textbx3">
#Html.TextAreaFor(model => model.domain_remarks, new { htmlAttributes = new { #class = "form-control", #rows = 2 } })
#Html.ValidationMessageFor(model => model.domain_remarks, "", new { #class = "text-danger" })
</div>
</div>
</li>
</ul>
</div>
My model
public int? domain_flag { get; set; }
[Display(Name = "Date of Renewal")]
[DataType(DataType.Date)]
[RequiredIf("domain_flag==1",ErrorMessage ="Enter Renew Date")]
public DateTime? domain_renew_date { get; set; }
[Display(Name = "Date of Expiry")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:mm/dd/yy}", ApplyFormatInEditMode = true)]
[RequiredIf("domain_flag==1", ErrorMessage = "Enter Expiry Date")]
public DateTime? domain_exp_date { get; set; }
[Display(Name = "Vendor")]
[RequiredIf("domain_flag==1", ErrorMessage = "Please Select Vendor")]
public int? domain_vendor_id { get; set; }
[Display(Name = "Amount(Rs.)")]
[RequiredIf("domain_flag==1", ErrorMessage = "Enter Amount")]
[RegularExpression("^[0-9]+$", ErrorMessage = "Enter Numeric Values")]
public decimal? domain_amt { get; set; }
[Display(Name = "Comments")]
public string domain_remarks { get; set; }
Global.asax
DataAnnotationsModelValidatorProvider.RegisterAdapter(
typeof(RequiredIfAttribute), typeof(RequiredIfValidator));
DataAnnotationsModelValidatorProvider.RegisterAdapter(
typeof(AssertThatAttribute), typeof(AssertThatValidator));
In this as soon as I select the radio button the required if error messages are displayed before entering the values. The error messages should be displayed on click of submit button before posting to the server. Is this possible with expressive annotations nuget package?
Yes it's possible with ExpressiveAnnotations.
#jwaliszko mentioned it.
You have to set the configuation of ea like this at client-side:
<script>
ea.settings.dependencyTriggers = '';

Resources