Parameter for "Delete" post method has blank attributes in ASP.NET MVC - asp.net-mvc

I'm having an issue in my MVC application (for making basic CRUD changes to a database) where the object parameter getting passed to my "Delete" post method has blank parameters, even though the object returned by the get method is correct. As a result, when I try to delete the object from the database I get the following exception:
A first chance exception of type 'System.ArgumentNullException' occurred in EntityFramework.dll
System.ArgumentNullException: Value cannot be null.
Parameter name: entity
at System.Data.Entity.ModelConfiguration.Utilities.RuntimeFailureMethods.Requires(Boolean condition, String userMessage, String conditionText)
at System.Data.Entity.DbSet`1.Remove(TEntity entity)
at MvcApplication1.HomeController.Delete(ISBN bookToDelete) in C:\Users\MMcCrimmon\Documents\Visual Studio 2012\Projects\MortonPublishingDatabaseInterface\MvcApplication1\Controllers\HomeController.vb:line 103
After a bit of digging I found this question: Missing something in "Delete" post method in MVC (EF 4.1), which seems to be identical, but the answers there did not resolve my problem. What am I doing wrong here?
Here's my controller code:
' GET: /Home/Delete/5
Function Delete(ByVal id As String) As ActionResult
Dim bookToDelete = _db.ISBNs.Find(id)
Return View(bookToDelete)
End Function
' POST: /Home/Delete/5
<HttpPost()> _
Function Delete(bookToDelete As ISBN) As ActionResult
Dim originalBook = _db.ISBNs.Find(bookToDelete.Product_Code)
Try
_db.ISBNs.Remove(originalBook)
_db.SaveChanges()
Return RedirectToAction("Index")
Catch exc As Exception
Return View(originalBook)
End Try
End Function
and here's the view for the Delete page:
#ModelType MvcApplication1.ISBN
#Code
ViewData("Title") = "Delete"
Layout = "~/Views/Shared/_Layout.vbhtml"
End Code
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<p/>
<fieldset>
<legend>ISBN</legend>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.Product_Code)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.Product_Code)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.Title)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.Title)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.ISBN_UPC)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.ISBN_UPC)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.ManualName)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.ManualName)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.PgCount)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.PgCount)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.BookSize)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.BookSize)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.ColorOrBW)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.ColorOrBW)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.PageCount)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.PageCount)
</div>
</fieldset>
#Using Html.BeginForm()
#Html.AntiForgeryToken()
#<p>
<input type="submit" value="Delete" /> |
#Html.ActionLink("Back to List", "Index")
</p>
End Using
Following the answer for Missing something in "Delete" post method in MVC (EF 4.1), here's the modified view (still doesn't work):
#ModelType MvcApplication1.ISBN
#Code
ViewData("Title") = "Delete"
Layout = "~/Views/Shared/_Layout.vbhtml"
End Code
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<p/>
#Using Html.BeginForm()
#Html.AntiForgeryToken()
#<fieldset>
<legend>ISBN</legend>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.Product_Code)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.Product_Code)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.Title)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.Title)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.ISBN_UPC)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.ISBN_UPC)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.ManualName)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.ManualName)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.PgCount)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.PgCount)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.BookSize)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.BookSize)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.ColorOrBW)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.ColorOrBW)
</div>
<div class="display-label">
<strong>#Html.DisplayNameFor(Function(model) model.PageCount)</strong>
</div>
<div class="display-field">
#Html.DisplayFor(Function(model) model.PageCount)
</div>
</fieldset>
#<p>
<input type="submit" value="Delete" /> |
#Html.ActionLink("Back to List", "Index")
</p>
End Using
Full disclosure: I'm new to MVC, ASP, and VB.NET, so please forgive me if I'm making some rookie mistake here...

You don't seem to be passing the "bookToDelete" parameter through to the DELETE method. In fact you shouldn't be passing this through as it's an object not a simple value. I would pass the "book id" through on delete post action (same as delete get action)
Altering the delete view form code by adding the following line between the #Using Html.BeginForm() and End Using lines
#Html.HiddenFor(model => model.id)
And change the DELETE post method in your controller to
Function Delete(id as string) As ActionResult
Dim originalBook = _db.ISBNs.Find(id)

You need to add a to your form indicating the parameter to pass to your controller.
E.g. If your controller is using "BookToDeleteID" as parameter name, your view html should look like this:
<form>
......
<input type="hidden" name="BookToDeleteID" value="A_NUMBER"/>
<input type="submit" value="delete"/>
</form>
Sometimes it has weird cases where you have to pass JSON objects to controllers. Maybe it's a data integrity concern by Microsoft. So I guess you have to parse the entire model for all actions.

Related

FormCollection inputs on action method have null values

I am trying to get values of form inputs on action method.
MVC View
#using (Html.BeginForm("Report", "Home"))
{
<div class="common_input Volunteer_input">
<div class="row">
<div class="col-sm-12">
<label for="firstName">Reporter:</label>
<div class="select_option_one">
<input type="text" id="ReporterCountries" class="ct-select2 ReporterCountriesList" />
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<label for="firstName">Partner:</label>
<div class="select_option_one">
<input type="text" name="PartnersCountries" id="PartnersCountries" class="ct-select2 CountryList" />
</div>
</div>
</div>
<h3>Comparators</h3>
<div class="row">
<div class="col-sm-12">
<label for="firstName">Partner:</label>
<div class="select_option_one">
<input type="text" name="CompareCountryList" id="CompareCountryList" class="ct-select2 CountryList" />
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<label for="firstName">Rank Growth:</label>
<div class="select_option_one">
<input type="text" name="RankGrowth" id="RankGrowth" class="ct-select2 RankGrowth" />
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="sub_submit">
<button type="submit" class="common_btn hvr-sweep-to-bottom">View<i class="fa fa-long-arrow-right"></i></button>
</div>
</div>
</div>
</div>
}
Action Method for Home Controller
public ActionResult Report(FormCollection form)
{
ViewData["ReporterCountries"] = Request.Form["ReporterCountries"];;
return RedirectToAction("Index","data");
}
When I try to retrieve the values of input on action controller I am receving all the control on the view but values are coming as null.

ASP .NET core razor view conditional display doesn't work as expected

I have a view where I conditionally iterate and print items: SPANs are not displayed (as expected).
<div>
#if (Model.SomeCondition)
{
#foreach (var x in Model.SomeData)
{
<span>#x.Title</span>
}
}
</div>
Now I'd like not to display the enclosing DIV, however it doesn't work: SPANs are still not displayed, but the DIV is. Why does this happen?
#if (Model.SomeCondition)
{
<div>
#foreach (var x in Model.SomeData)
{
<span>#x.Title</span>
}
</div>
}
This is the full view code:
#using Team.L
#using Microsoft.AspNetCore.Mvc.Localization
#inject IViewLocalizer Localizer
#model Team.ViewModels.DeptTaskGroupView
#{
var EventHandler = "Aventin." + ViewBag.AspAction + "(event)";
}
<form asp-controller="ModulesEx" asp-action="#ViewBag.AspAction" onsubmit="return false">
<div class="form-horizontal">
<input type="hidden" asp-for="Errors">
<div class="MessageBox">#Html.Raw(Utility.GetMessage(Model))</div>
<div class="form-group col-md-offset-2">
<label class="col-md-2"></label>
<div class="col-md-10">
<span data-valmsg-for="" class="text-danger" />
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">#MyText.Department</label>
<div class="col-md-10">
<select asp-for="DepartmentID" class="form-control" asp-items="#Model.DepartmentList" onchange="#EventHandler"></select>
<span asp-validation-for="DepartmentID" class="text-danger" />
</div>
</div>
#if (Model.AssignedTaskGroup != null)
{
<div class="form-group">
<label class="col-md-2 control-label">#MyText.TaskGroup</label>
<div class="col-md-10">
#foreach (var x in Model.AssignedTaskGroup)
{
<input type="checkbox" name="selectedItems" value="#x.ID" #(Html.Raw(x.Assigned ? "checked=\"checked\"" : "")) />
#x.Title
}
</div>
</div>
}
<div class="form-horizontal">
<div class="form-group">
<div class="col-md-1 col-md-offset-2">
<input type="submit" value="#MyText.Save" class="btn btn-default" />
</div>
</div>
</div>
</div>
</form>
As written, it doesn't happen. I'm guessing you either didn't reload the page or there is code around your demonstrated code that renders a div that this div is contained in.

how to simultaneously pass A model as well as a File to the controller?

i have a reports model in my MVC project. Now i have to send a file to the controller simultaneously. I am using HttpPostedFileBase as parameter with my reports model.
Reports Model is :
Public Class ReportsModel
Public Sub New()
Authentication = "private"
End Sub
Private UploadDate_ As String
<Display(Name:="ID")> _
Public Property id As UInteger
<Display(Name:="Serial Number")> _
Public Property Srno As UInteger
<Display(Name:="User Name")> _
Public Property UserName As String
<Display(Name:="Details")> _
Public Property Details As String
End Class
And My Controller is :
<HttpPost()> _
<AllowAnonymous()> _
<ValidateAntiForgeryToken()> _
Public Function EditReport(ByVal mdl As ReportsModel, ByVal FileUpl As HttpPostedFileBase ) As ActionResult
Return View(mdl)
End Function
Here is my View:
<% Using Html.BeginForm() %>
<%: Html.AntiForgeryToken() %>
<%: Html.ValidationSummary(True) %>
<fieldset>
<legend>ReportsModel</legend>
<%: Html.HiddenFor(Function(model) model.id) %>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.Srno) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(Function(model) model.Srno) %>
<%: Html.ValidationMessageFor(Function(model) model.Srno) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.UserName) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(Function(model) model.UserName) %>
<%: Html.ValidationMessageFor(Function(model) model.UserName) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.Details) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(Function(model) model.Details) %>
<%: Html.ValidationMessageFor(Function(model) model.Details) %>
</div>
<%--This Code Below is running correctly on passing it , But not with Reports Model--%>
<form action="/phed/EditReport" method="post" enctype="multipart/form-data">
<label for="FileUpl1">Upload File: </label>
<input type="file" name="FileUpl" id="FileUpl" />
<span style="color: red;"><%:TempData("Message")%></span>
<p>
<input type="submit" value="Save" />
</p>
</form>
</fieldset>
<% End Using %>
How to send this FileUpl along with ReportsModel to the controller ? I Can Not change reports Model.
I got it. I have Change the form action and enctype to "multipart/form-data". Like:
<div>
<form action="/phed/EditReport" method="post" enctype="multipart/form-data">
<%: Html.AntiForgeryToken() %>
<%: Html.ValidationSummary(True) %>
<fieldset>
<legend>ReportsModel</legend>
<%: Html.HiddenFor(Function(model) model.id) %>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.Details) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(Function(model) model.Details) %>
<%: Html.ValidationMessageFor(Function(model) model.Details) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.BillsOfMonth) %>
</div>
<div class="editor-field">
<%: Html.TextBox("BillsOfMonth", Model.BillsOfMonth, New With {Key .class = "monthpicker"})%>
<%: Html.ValidationMessageFor(Function(model) model.BillsOfMonth) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.UplDate) %>
</div>
<div class="editor-field">
<%: Html.TextBox("UplDate", Model.UplDate, New With {Key .class = "datepicker"})%>
<%: Html.ValidationMessageFor(Function(model) model.UplDate) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.Authentication) %>
</div>
<div class="editor-field">
<%: Html.DropDownList("Authentication", New List(Of SelectListItem) From { _
New SelectListItem With {.Text = "public", .Value = "public"}, _
New SelectListItem With {.Text = "private", .Value = "private"}})%>
<%: Html.ValidationMessageFor(Function(model) model.Authentication) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.Download) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(Function(model) model.Download, New With {Key .readonly = "readonly"})%>
<%: Html.ValidationMessageFor(Function(model) model.Download) %>
</div>
<label for="FileUpl1">Upload File: </label>
<input type="file" name="FileUpl" id="FileUpl" />
<span style="color: red;"><%:TempData("Message")%></span>
<input type="submit" class="sort-submit" value="Upload File" />
</fieldset>
</form>
</div>
It seems you create a form nested to another form which is not allowed in HTML, so if you want to upload your file, you have to remove the second Form. The BeginForm method renders a form that will be handled by a controller action method.
You can use this method in a using block. In that case, the method renders the closing tag at the end of the using block.
And you can do like this:
<% Using Html.BeginForm("EditReport","phed",Nothing,FormMethod.Post, New With {.enctype="multipart/form-data"}) %>
<%: Html.AntiForgeryToken() %>
<%: Html.ValidationSummary(True) %>
<fieldset>
<legend>ReportsModel</legend>
<%: Html.HiddenFor(Function(model) model.id) %>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.Srno) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(Function(model) model.Srno) %>
<%: Html.ValidationMessageFor(Function(model) model.Srno) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.UserName) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(Function(model) model.UserName) %>
<%: Html.ValidationMessageFor(Function(model) model.UserName) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(Function(model) model.Details) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(Function(model) model.Details) %>
<%: Html.ValidationMessageFor(Function(model) model.Details) %>
</div>
<%--This Code Below is running correctly on passing it , But not with Reports Model--%>
<label for="FileUpl1">Upload File: </label>
<input type="file" name="FileUpl" id="FileUpl" />
<span style="color: red;"><%:TempData("Message")%></span>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% End Using %>
I hope it will help.

Using nested beginform in MVC

I have scenario where I have load data on dropdown selection change and after manipulation I have to submit the page for saving.
I have developed the page but since I new to MVC so can anyone verify me code and can suggest better approach of doing the same.
#using (Html.BeginForm("Save", "forecast"))
{
using (Html.BeginForm("YearChange", "forecast", FormMethod.Get, new {#id="frmYearChange" }))
{
<div class="span12">
<div class="well well-sm" style="padding-bottom: 0px !important;">
<div class="span5">
<div class="control-group">
<label class="control-label" for="selectGroup">
Select Group:</label>
<div class="controls">
#Html.DropDownListFor(m => m.groupId, Model.groupList, "--Select Group--", new { #id = "selectGroup" })
</div>
</div>
</div>
<div class="span5">
<div class="control-group">
<label class="control-label" for="selectYear">
Select Year:</label>
<div class="controls">
#Html.DropDownListFor(m => m.yearId, Model.yearList, "--Select Year--", new { #id = "selectYear", onchange = "selectYear_indexChanged();" })
</div>
</div>
</div>
<div class="clearfix">
</div>
</div>
</div>
}
.....
}
You can't have nested forms. You can however have multiple forms per view.
See W3C for more info.

How to pass Membership object as a model to view?

I am trying to get all of the information for the user into a view with a form to edit the user's information. I have this controller action:
'
' GET: /Account/EditRegistry/5
Public Function EditRegistry(Optional id As String = Nothing) As ActionResult
' get user model
Dim model = Membership.GetUser(id)
' pass username to view
ViewData("UserName") = id
Return View(model)
End Function
And, I am using this view:
#ModelType MyBlog.RegisterModel
#Code
ViewData("Title") = "Register"
End Code
<h2>Create a New Account</h2>
<p>
Use the form below to create a new account.
</p>
<p>
Passwords are required to be a minimum of #Membership.MinRequiredPasswordLength characters in length.
</p>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#Using Html.BeginForm()
#Html.ValidationSummary(True, "Account creation was unsuccessful. Please correct the errors and try again.")
#<div>
<fieldset>
<legend>Account Information</legend>
#Html.Hidden("m.UserName", ViewData("UserName"))
<div class="editor-label">
#Html.LabelFor(Function(m) m.Email)
</div>
<div class="editor-field">
#Html.TextBoxFor(Function(m) m.Email)
#Html.ValidationMessageFor(Function(m) m.Email)
</div>
<div class="editor-label">
#Html.LabelFor(Function(m) m.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(Function(m) m.Password)
#Html.ValidationMessageFor(Function(m) m.Password)
</div>
<div class="editor-label">
#Html.LabelFor(Function(m) m.ConfirmPassword)
</div>
<div class="editor-field">
#Html.PasswordFor(Function(m) m.ConfirmPassword)
#Html.ValidationMessageFor(Function(m) m.ConfirmPassword)
</div>
<div class="editor-label">
#Html.LabelFor(Function(m) m.Company, "Companies")
</div>
<div class="editor-field">
#Html.DropDownList("Company", String.Empty)
#Html.ValidationMessageFor(Function(m) m.Company)
</div>
<div class="editor-label">
#Html.LabelFor(Function(m) m.IsCompanyOwner, "Company Owner?")
</div>
<div class="editor-field">
#Html.CheckBoxFor(Function(m) m.IsCompanyOwner)
#Html.ValidationMessageFor(Function(m) m.IsCompanyOwner)
</div>
<div class="editor-label">
#Html.LabelFor(Function(m) m.Blog, "Blogs")
</div>
<div class="editor-field">
#Html.DropDownList("Blog", String.Empty)
#Html.ValidationMessageFor(Function(m) m.Blog)
</div>
<div class="editor-label">
#Html.LabelFor(Function(m) m.IsBlogOwner, "Blog Owner?")
</div>
<div class="editor-field">
#Html.CheckBoxFor(Function(m) m.IsBlogOwner)
#Html.ValidationMessageFor(Function(m) m.IsBlogOwner)
</div>
<p>
<input type="submit" value="Register" />
</p>
</fieldset>
</div>
End Using
The error I get is:
The model item passed into the dictionary is of type
'System.Web.Security.MembershipUser', but this dictionary requires a
model item of type 'MyBlog.RegisterModel'.
How can I resolve this error and get the user's info into the model and into the form in the view?
The error message is pretty self explanatory. Your view is strongly typed to MyBlog.RegisterModel but you are passing MembershipUser which is what the Membership.GetUser method returns. So go ahead and pass the correct model type to your view:
Public Function EditRegistry(Optional id As String = Nothing) As ActionResult
' get user model
Dim model = Membership.GetUser(id)
' build a view model
Dim viewModel = New RegisterModel()
viewModel.Email = model.Email
' pass username to view
ViewData("UserName") = id
Return View(viewModel)
End Function

Resources