HttpPost Delete MVC for Composite Keys - asp.net-mvc

I have a table with three columns with first two formulating the composite key
SrcSys (CompositeKey Part I)
CustId (CompositeKey Part II)
CustNm
I am new to ASP & starting with MVC Core.
The following code for get method works well:
public async Task<IActionResult> Delete(string _SrcSys, string _CustId)
{
if (_SrcSys == null || _CustId == null)
{
return NotFound();
}
var customer = await _context.Customers.SingleOrDefaultAsync(Cust => Cust.SrcSys == _SrcSys && Cust.CustId == _CustId);
if (customer == null)
{
return NotFound();
}
return View(customer);
}
The relevant code of Delete.cshtml is:
#model RiskDotNet.Models.Customer
#{
ViewData["Title"] = "Delete";
}
#*<h2>Delete</h2>*#
<br />
<hr />
<dl class="dl-horizontal">
<dt>
Src Sys
</dt>
<dd>
#Html.DisplayFor(model => model.SrcSys)
</dd>
<dt>
Cust ID
</dt>
<dd>
#Html.DisplayFor(model => model.CustId)
</dd>
<dt>
Customer
</dt>
<dd>
#Html.DisplayFor(model => model.CustNm)
</dd>
</dl>
<form asp-action="Delete">
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" />
<p />
<p />
<input type="submit" value="Cancel" class="btn btn-default" a asp-action="Index">
</div>
</form>
All the three fields are appearing on the page.
In respect of HttpPost what would be a reasonable piece of code?

You need to put the SrcSys and CustId in the form so they can be passed to the backend on the submit.
You can just put this in the form part:
#Html.HiddenFor(model => model.SrcSys)
#Html.HiddenFor(model => model.CustId)
These properties wont be displayed but they will be submitted.
Sidenote
Dont use Html helpers ( #Html.DisplayFor, #Html.HiddenFor..) they are the old way of doing things.
Use tag helpers that came with MVC Core:
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro

I resolved the problem myself:
Updated HttpPost:
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeletePost(Customer customer)
{
try
{
_context.Entry(customer).State = EntityState.Deleted;
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
catch (DbUpdateConcurrencyException)
{
return RedirectToAction("Delete", new { ss = customer.SrcSys, ci = customer.CustId });
}
}
and Updated Delete.cshtml:
#model RiskDotNet.Models.Customer
#{
ViewData["Title"] = "Delete";
}
<hr />
<dl class="dl-horizontal">
<dt>
Src Sys
</dt>
<dd>
#Html.DisplayFor(model => model.SrcSys)
</dd>
<dt>
Cust ID
</dt>
<dd>
#Html.DisplayFor(model => model.CustId)
</dd>
<dt>
Customer
</dt>
<dd>
#Html.DisplayFor(model => model.CustNm)
</dd>
</dl>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.SrcSys)
#Html.HiddenFor(model => model.CustId)
<form asp-action="Delete">
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" />
<p />
<p />
<input type="submit" value="Cancel" class="btn btn-default" a asp-action="Index">
</div>
</form>
}
Did the job!!!
:-)

Related

Transfering Id Data From View To Partial View And Then To Controller In .NET MVC Web App

I am trying to send an Event id (Model name is event) from my event view to a partial view in which you could comment on that related event (which is encuptulated by that view and rendered via ajax) then to the post controller action of that partial view which will assign eventId to comment id for db relation. View and partial view has different models. How could i manage that?
DIAGRAM OF WORKFLOW
View -> Partial View -> Controller | | |
Model1(Event) - Model2(Comment)- Post action that'll get Id from Model1 as argument.
(Detail) - (CreateComment) - (Comment Controller - Create)
Event.Id -> Sent to partial view -> On Post action(create comment), Id will be sent to action.
VIEW CODE
#using Evented.Domain.Models
#using Microsoft.AspNetCore.Identity
#model Evented.Web.EventVMCompany
#inject UserManager<User> UserManager
#{
ViewData["Title"] = "Detail";
}
<h1>Detail</h1>
<h4>EventVM</h4>
<hr />
#Html.ValidationMessageFor(m => m.Id)
<form asp-action="JoinEvent">
<div>
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Id)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Id)
#Html.HiddenFor(model=>model.Id)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Topic)
#Html.HiddenFor(model=>model.Topic)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Topic)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Title)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Title)
#Html.HiddenFor(model=>model.Title)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Description)
#Html.HiddenFor(model=>model.Description)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Description)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Location)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Location)
#Html.HiddenFor(model=>model.Location)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.BeginsAt)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.BeginsAt)
#Html.HiddenFor(model=>model.BeginsAt)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.EndsAt)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.EndsAt)
#Html.HiddenFor(model=>model.EndsAt)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.joineeLimit )
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.joineeLimit)
#Html.HiddenFor(model=>model.joineeLimit)
</dd>
#Html.HiddenFor(model=>model.CreatorId)
#Html.HiddenFor(model=>model.joineeNumber)
#Html.HiddenFor(model=>model.UsersJoined)
#Html.HiddenFor(model=>model.UsersJoined.Count)
</dl>
</div>
#{
if (Model.CreatorId != UserManager.GetUserId(User))
{
#foreach (var item in Model.UsersJoined)
{
#if (item.UserId != UserManager.GetUserId(User))
{
<button type="submit" class="btn btn-primary">Join</button>
}
else
{
<button type="submit" formaction="/Event/LeaveEvent" class="btn btn-primary">Leave</button>
}
}
#if (Model.UsersJoined.Count == 0)
{
<button type="submit" class="btn btn-primary">Join</button>
}
}
}
</form>
<a asp-action="Index" class="btn btn-primary">Back to List</a>
<div>#{
foreach (var item in Model.UsersJoined)
{
if (item.UserId == UserManager.GetUserId(User))
{
<div id="commentlist"></div>
}
}
}</div>
<div id="createcomment"></div>
<script type="text/javascript">
$('#createcomment').load('#Url.Action("Create","Comment", ViewData["EventId"] )');
$('#commentlist').load('#Url.Action("Index","Comment")');
</script>
PARTIAL VIEW CODE
#model Evented.Web.CommentVM
<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">
<input asp-for="Text" class="form-control" placeholder="Comment"/>
<span asp-validation-for="Text" class="text-danger"></span>
</div>
<div class="form-group">
<input name="button" id="button" type="submit" value="Comment" class="btn btn-primary " />
</div>
</form>
</div>
</div>
CONTROLLER ACTION CODE
[HttpPost]
[ValidateAntiForgeryToken]
public async Task< ActionResult> Create(CommentVM commentVM,int eventId)
{
User usr= usrManager.GetUserAsync(User).Result;
var comment = mapper.Map<Comment>(commentVM);
comment.EventId= eventId;
comment.User = usr;
comment.CreatedAt= DateTime.Now;
comment.UpdatedAt= DateTime.Now;
await commentService.AddCommentAsync(comment);
return RedirectToAction("Index");
}
GITHUB OF PROJECT - https://github.com/kocfurkan/Evented
Codes provided is all i could.
Please try to pass data like this:
EventController:
public async Task<IActionResult> Detail(int id)
{
ViewData["EventId"] = id;
//.....
}
Detail.cshtml:
//...
<script type="text/javascript">
$('#createcomment').load('#Url.Action("Create","Comment", new {id= ViewData["EventId"]} )');
//...
</script>
CommentController:
public ActionResult Create(int id)
{
return PartialView("_PartialPageCreate", new CommentVM() { EventId = id});
}
_PartialPageCreate.cshtml:
<div class="form-group">
//Add a hidden input
<input name="eventId" type="hidden" value="#Model.EventId" />
<input asp-for="Text" class="form-control" placeholder="Comment"/>
<span asp-validation-for="Text" class="text-danger"></span>
</div>
Test Result:

ASP.NET MVC delete method pass an Id / model to the controller

Using Razor pages for my views, I can't find a way to pass an Id / bounded model to my controller.
I have created a delete template view with my model, added a delete action method to my controller, but I can't figure out how to pass any parameters.
#model AdventureWorks.Models.HumanResources.Department
#{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
#using (Html.BeginForm("DeleteConfirmed", "Department", FormMethod.Post))
{
#Html.AntiForgeryToken()
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Department</h4>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
#Html.DisplayFor(model => model.Name)
</dd>
<dt>
#Html.DisplayNameFor(model => model.GroupName)
</dt>
<dd>
#Html.DisplayFor(model => model.GroupName)
</dd>
<dt>
#Html.DisplayNameFor(model => model.ModifiedDate)
</dt>
<dd>
#Html.DisplayFor(model => model.ModifiedDate)
</dd>
</dl>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Delete" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Controller
public ActionResult DeleteConfirmed(Department department)
{
return ViewDepartments();
}
The Department object that is returned, is a new object with no properties set.
Could you advise me, how to pass at least an Id of the to be deleted object?
I managed to get the model with the form on my create and update method, but I can't figure out, how to do the same on delete.
You can add the parameters you want to pass in Html.BeginForm.Here is a demo:
#using (Html.BeginForm("DeleteConfirmed", "Department",new { Id=Model.Id}, FormMethod.Post))
{
...
}
result:
And you don't need to add #Html.AntiForgeryToken(),because your form method is post.
DisplayFor will not do the Model binding.
Assuming Id is a key of Department, add
#Html.HiddenFor(model => model.Id)
inside of Html.BeginForm.
Inside of you delete action use department.Id to find and delete the item.
You have to pass some value to your controller.
#using (Html.BeginForm("DeleteConfirmed", "Department", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Id) // Use valid expression for id property
...
}
And change signature of DeleteConfirm method to
public ActionResult DeleteConfirmed(int id) // Use valid id property type
{
// Delete object
}
That should do the trick.

ASP .Net MVC: Razor view ignores or skips validation ViewBag

I am trying to have validation for my Search option field, which is inside Index.cshtml :
When I enter name it works fine and displays all matching results inside DetailsBySurname.cshtml :
This is DetailsBySurname.cshtml
This Razor view supposed to show Validation Success or Error messages depending on whats inside the ViewBag, but when it redirects from Controller IActionResult to my Razor View with Error Messages inside ViewBag it skips(i think) the block of code with if statement and goes directly to foreach loop which is supposed to be activated only when there are NO Error messages. Then i get this error:
Here is Code for the Razor view DetailsBySurname.cshtml:
#model IEnumerable<codeRed_Capstone.Models.Employee>
#{
ViewData["Title"] = "DetailsBySurname";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#if (ViewBag.Message != null)
{
<p class="alert-#(ViewBag.Error != null ? "danger" : "success")">#(ViewBag.Message)</p>
if (ViewBag.Error != null)
{
<ul>
#foreach (Exception e in ViewBag.Exception.ValidationExceptions)
{
<li class="alert-danger">#(e.Message)</li>
}
</ul>
}
}
<h1>Details</h1>
<div>
<h4>Employee</h4>
<hr />
#foreach (var item in Model)
{
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(item => item.FirstName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(modelItem => item.FirstName)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => item.LastName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(modelItem => item.LastName)
</dd>
</dl>
}
</div>
This is block of code from Controller for the IAction result DetailsBySurname:
public async Task<IActionResult> DetailsBySurname(string lastName)
{
if (Request.Query.Count > 0)
{
try
{
ValidationException exception = new ValidationException();
lastName = !string.IsNullOrWhiteSpace(lastName) ? lastName.Trim() : null;
using (CompanyContext context = new CompanyContext())
{
if (string.IsNullOrWhiteSpace(lastName))
{
exception.ValidationExceptions.Add(new Exception("Last Name Not Provided"));
}
// Category ID fails parse.
// Common validation points (5) and (5a).
int n;
bool isNumeric = int.TryParse(lastName, out n);
if (isNumeric)
{
exception.ValidationExceptions.Add(new Exception("ID Not Valid string"));
}
else
{
// Category ID exists.
// Common validation point (7).
if (!context.Employees.Any(x => x.LastName == lastName))
{
exception.ValidationExceptions.Add(new Exception("Last Name Does Not Exist"));
}
}
if (exception.ValidationExceptions.Count > 0)
{
throw exception;
}
}
var employees = _context.Employees.Where(m => m.LastName == lastName);
ViewBag.Message = $"Successfully Found {lastName}!";
return View(employees);
}
// Catch ONLY ValidationException here.
catch (ValidationException e)
{
ViewBag.LastName = lastName;
ViewBag.Message = "There exist problem(s) with your submission, see below.";
ViewBag.Exception = e;
ViewBag.Error = true;
return View(e);
}
}
return View();
}
finally here is code for the search field inside Index.cshtml view:
#model IEnumerable<codeRed_Capstone.Models.Employee>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
</li>
<li class="nav-item dropdown">
<form action="/Employee/Index" method="get">
<lable for="filter"> Show Laid of Staff</lable>
<input type="checkbox" id="filter" name="filter" value="laidoff" />
<input class="btn btn-outline-success my-2 my-sm-0" type="submit" value="Go!" />
</form>
</li>
</ul>
<form action="/Employee/DetailsByEmail" method="get" class="form-inline my-2 my-lg-0">
<input id="email" name="email" data-val="true" data-val-required="Email is required" class="form-control mr-sm-2" type="search" placeholder="Search by Email" aria-label="Search">
<span class="field-validation-valid" data-valmsg-for="email" data-valmsg-replace="true"></span>
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
<form action="/Employee/DetailsBySurname" method="get" class="form-inline my-2 my-lg-0">
<input id="lastName" name="lastName" data-val="true" data-val-required="Last Name is required" class="form-control mr-sm-2" type="search" placeholder="Search by Last Name" aria-label="Search">
<span class="field-validation-valid" data-valmsg-for="lastName" data-valmsg-replace="true"></span>
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
I watched debugging it works as expected goes all the way till the end, only when it jumps to Razor View it gives me this error that i mentioned above.
I also have Class created to handle all Validation exceptions but its working fine. I'm sure problem is some where here between Controller and Razor view. Or maybe problem somewhere else, i'm new to ASP .Net MVC, any suggestions?
I fixed it with a different validation approach.
For the DetailsBySurname i removed if(ViewBag... and added different if(ViewData... - statement to check if returned result is null then don't run foreach loop). To catch error messages use another if statement #if(!ViewData.ModelState.IsValid) like this:
#model IEnumerable<codeRed_Capstone.Models.Employee>
#{
ViewData["Title"] = "DetailsBySurname";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Details</h1>
<div>
#if (ViewData.ModelState.IsValid)
{
<h4>Employee</h4>
<hr />
#foreach (var item in Model)
{
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(item => item.FirstName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(modelItem => item.FirstName)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(item => item.LastName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(modelItem => item.LastName)
</dl>
}
}
</div>
<div class="form-row">
<div class="form-group col-md-2">
#if (!ViewData.ModelState.IsValid)
{
<span class="field-validation-error">#ViewData.ModelState["LastName"].Errors[0].ErrorMessage</span>
}
</div>
</div>
Then inside Controller for the IAction result DetailsBySurname I changed validation method to built-in validation which looks something like this:
public async Task<IActionResult> DetailsBySurname(string lastName)
{
lastName = !string.IsNullOrWhiteSpace(lastName) ? lastName.Trim() : null;
if (string.IsNullOrWhiteSpace(lastName))
{
ModelState.AddModelError("LastName", "Last Name not Provided");
//exception.ValidationExceptions.Add(new Exception("Last Name Not Provided"));
}
bool exists;
if (!(exists = _context.Employees.Any(m => m.LastName == lastName)))
{
//return NotFound(new Exception("Email not found"));
ModelState.AddModelError("LastName", "Last Name not found");
}
if (!ModelState.IsValid)
{
return View();
}
else
{
var employee = _context.Employees.Where(m => m.LastName == lastName);
return View(employee);
}
}

MVC 5 ActionResult parameter always null

I'm pretty newbie with MVC and my English is very poor. I'm now stuck with a parameter always being null in my ActionResult parameter.
Here is the controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "TimeCodeId, Code, Title, Description, IsValid, DateCreated")] TimeCodeInfo infoTimeCode, string submitButton)
{
bool result;
switch (submitButton)
{
case "Update":
case "Enregistrer":
infoTimeCode.LastDateModified = DateTime.Now;
result = _mTimeCode.Update(infoTimeCode);
return RedirectToAction("List");
case "Cancel":
case "Annuler":
return RedirectToAction("List");
//break;
}
return View(infoTimeCode);
}
and this is the cshtml
#using (Html.BeginForm("Edit", "TimeCode", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(Model => Model.TimeCodeId)
<table class="w3-table w3-card">
<tr>
<td>Code:</td>
<td>
#Html.EditorFor(model => model.Code)
#Html.ValidationMessageFor(model => model.Code)
</td>
</tr>
<tr>
<td>Titre:</td>
<td>
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</td>
</tr>
<tr>
<td>Description:</td>
<td>
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</td>
</tr>
<tr>
<td>Est valide ?</td>
<td>
#Html.EditorFor(model => model.IsValid)
#Html.ValidationMessageFor(model => model.IsValid)
<label class="switch" onsubmit="#Model.IsValid = getCheckBoxValue('switchCheckBox')">
<input id="switchCheckBox" type="checkbox" name="IsValid">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>Date de création:</td>
<td>#Model.DateCreated</td>
</tr>
<tr>
<td>Dernière modification:</td>
<td>#Model.LastDateModified</td>
</tr>
</table>
<br />
<i class="fa fa-caret-left"></i> Retour à la liste
<div class="float-right">
<button type="submit" value="enregistrer"> enregistrer </button>
#*<a type="submit" href="~/Views/TimeCode/List.cshtml" class="w3-right w3-round-medium button buttonBlue">Enregistrer</a>*#
Annuler
</div>
}
Parameter submitButton is always null when I debug it. Is someone seeing where the problem is? Do I have to add more details?
Thank you!

asp.net mvc 4 - form submit button not responding

I am new to MVC and is using MVc4 with VS2013. This is my controller:
[HttpPost]
public ActionResult Create(CreateRequestViewModel viewModel)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View(viewModel);
}
Below is my view:
#model ProMs.Web.ViewModels.CreateRequestViewModel
#{
ViewBag.Title = "Create";
}
<body>
<h2>New Request</h2>
<h3></h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<div class="float-left">
<label for="RequestName">Request</label>
#Html.EditorFor(model => model.Request.RequestName)
#Html.ValidationMessageFor(model => model.Request.RequestName)
#Html.LabelFor(model => model.Request.Requestor)
#Html.EditorFor(model => model.Request.Requestor)
#Html.ValidationMessageFor(model => model.Request.Requestor)
#Html.LabelFor(model => model.Request.Purpose)
#Html.EditorFor(model => model.Request.Purpose)
#Html.ValidationMessageFor(model => model.Request.Purpose)
</div>
<div class="float-right">
#Html.LabelFor(model => model.Request.Investigator)
#Html.EditorFor(model => model.Request.Investigator)
#Html.ValidationMessageFor(model => model.Request.Investigator)
#Html.LabelFor(model => model.Request.Department)
#Html.EditorFor(model => model.Request.Department)
#Html.ValidationMessageFor(model => model.Request.Stage)
#Html.LabelFor(model => model.Request.Comment)
#Html.EditorFor(model => model.Request.Comment)
#Html.ValidationMessageFor(model => model.Request.Comment)
</div>
#Html.HiddenFor(model => model.Request.RequestID)
#Html.HiddenFor(model => model.Request.DateCreated)
#Html.HiddenFor(model => model.Request.CreatedBy)
</fieldset>
}
<p>
<input type="submit" value="Submit" />
</p>
</body>
Nothing happened if "submit" button is clicked. I even cold not put a breaking point at the line
.
Thanks very much for your help.
Hugh
#Html.BeginForm() creates a <form> element. Right now your submit button is outside of this element, so move it inside.
}
<p>
<input type="submit" value="Submit" />
</p>
Should be
<p>
<input type="submit" value="Submit" />
</p>
} <-- This goes down here

Resources