I have a view that is designed to delete from the database.
The view is populated correctly. When I click the Delete button, the ID on the view is not passed to the controller. When I have a breakpoint in the controller has received a null
value from the view.
In the view when I removed the hidden from this <input asp-for="Form.Id" hidden />
the Id
is visible. Yet when I click on the Delete button, the Id
passed is null
.
My model:
namespace PricingParameters.Models
{
public class Form
{
[Key]
public int Id { get; set; }
[Required]
[Display(Name = "Branch")]
public int BranchId { get; set; } = 0;
[ValidateNeverAttribute]
public Branch Branch { get; set; }
[Required]
public int FormTypeId { get; set; } = 0;
[ValidateNeverAttribute]
public FormType FormType { get; set; }
[Required]
[Display(Name = "Form Cost")]
[DisplayFormat(DataFormatString = "{0:N2}", ApplyFormatInEditMode = true)]
public double Value { get; set; } = 0;
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Modified Date")]
public DateTime ModifedDateTime { get; set; } = DateTime.Now;
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Created Date")]
public DateTime CreatedDateTime { get; set; } = DateTime.Now;
}
}
My view model:
namespace PricingParameters.Models.ViewModels
{
public class FormVM
{
public required Form Form { get; set; }
[ValidateNever]
public required IEnumerable<SelectListItem> BranchList { get; set; }
[ValidateNever]
public required IEnumerable<SelectListItem> FormTypeList { get; set; }
}
}
My view:
@model PricingParameters.Models.ViewModels.FormVM
@{
ViewData["Title"] = "Form Cost Delete";
}
<form method="post" asp-action="Delete">
<input asp-for="Form.Id" hidden />
<div class="border p-3 mt-4">
<div class="row pb-2">
<h2 class="text-primary">Delete Form Cost</h2>
<hr />
</div>
<div class="mb-3">
<label asp-for="Form.BranchId"></label>
<select asp-for="Form.BranchId" disabled asp-items="@Model.BranchList" class="form-select">
<option disabled selected>--Branch--</option>
</select>
</div>
<div class="mb-3">
<label asp-for="Form.FormTypeId"></label>
<select asp-for="Form.FormTypeId" disabled asp-items="@Model.FormTypeList" class="form-select">
<option disabled selected>--Form Type--</option>
</select>
</div>
<div class="mb-3">
<label asp-for="Form.Value"></label>
<input asp-for="Form.Value" disabled class="form-control" />
</div>
<button type="submit" class="btn btn-primary" style="width:150px">Delete</button>
<a asp-controller="Form" asp-action="Index" class="btn btn-secondary" style="width:150px">
Back to List
</a>
</div>
</form>
The Delete
action in my FormController
:
// POST
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeletePOST(int? id)
{
var obj = _unitOfWork.Form.GetFirstOrDefault(u => u.Id == id);
if (obj == null)
{
TempData["error"] = "Form Cost not deleted";
return RedirectToAction(nameof(Index));
}
_unitOfWork.Form.Remove(obj);
_unitOfWork.Save();
TempData["success"] = "Form Cost deleted successfully";
return RedirectToAction(nameof(Index));
}
This code is almost a character-by-character from another model that works.
The <input asp-for="Form.Id" hidden />
tag helper used in the question above will generate the following HTML:
<input hidden type="number" id="Form_Id" name="Form.Id" data-val-required="The Id field is required." ...
As we can see the generated name is name="Form.Id"
. This is why the binding doesn't work properly, because of on the server side the expected name is defined as id
.
To fix this problem define the tag name explicitly:
<input asp-for="Form.Id" name="id" hidden />