C# MVC form does not send data back to controller - c#

I know it must be something stupid, but I cant seem to figure this out. I have the following in a view:
#using (#Html.BeginForm("ReceiveForm1", "Home", FormMethod.Post))
{
<div class="form-group">
<label for="organizationID">Organization ID</label>
<input type="number" class="form-control" asp-for="organizationID" aria-describedby="emailHelp" placeholder="Enter Organization ID">
</div>
<div class="form-group">
<label for="externalPersonalID">External Personal ID</label>
<input type="number" class="form-control" asp-for="externalPersonalID" placeholder="Enter External Personal ID">
</div>
<div class="form-group">
<label for="phoneNumber">Phone Number</label>
<input type="number" class="form-control" id="phoneNumber" asp-for="phoneNumber" placeholder="Password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
}
And I have the following code in my controller:
[HttpPost]
public ActionResult ReceiveForm1(FormCollection collection)
{
IEnumerable<Form1Return> personData = GetPersonInformation(collection);
return View(personData);
}
When I run the code, and enter data into the form, and click the submit button, I run to a breakpoint set on call to GetPersonInformation. When I do a watch on collection, there are no elements. So for some reason, the form data is not making it to the controller. Any idea why?
Thanks.

The 'Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FormCollectionModelBinder' cannot bind to a model of type 'Microsoft.AspNetCore.Http.FormCollection'. Change the model type to 'Microsoft.AspNetCore.Http.IFormCollection' instead.
Please try this:
[HttpPost]
public ActionResult ReceiveForm1(IFormCollection collection)
{
IEnumerable<Form1Return> personData = GetPersonInformation(collection);
return View(personData);
}

I've seen this happen when input's don't have their name attribute set. The relevant section on W3Schools has this nugget which confirms this is likely the case.
Note: Only form elements with a name attribute will have their values passed when submitting a form.

Related

Data annotation validation happening on page load in ASP.Net Core

I am facing the issue of data validation being executed on load of a new page even though it is clearly coming from a Get method. Is there something that's triggering the validations on page load?
I have a button on a view to add a new Student record in the new screen :
View :
<a type="button" id="btnAddStudent" href='#Url.Action("Details","Student")' class="btn btn-tertiary" title="Add Student">Add Student</a>
The controller code for the Details action method in Student Controller is as follows.
[HttpGet]
public ActionResult Details(StudentInfo model)
{
//This is populating the model parameters as expected.
helper.StudentInfo(ref model);
return View(model);
}
The view for the Details screen is as follows. The page loads but is throwing validation errors even though it's a Get method.
<form id="frmSubmit" asp-action="Details" asp-controller="Student" method="post">
<input type="hidden" asp-for="StudentId" />
<div class="row">
<div class="col-xs-12">
#Html.ValidationSummary("", new { #class = "alert alert-danger validation" })
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="Name">*StudentName</label><br />
<input asp-for="Name" class="form-control" maxlength="100" placeholder="Enter student name..." />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="AddressLine1"></label><br />
<input asp-for="AddressLine1" class="form-control" placeholder="Enter address..." />
<span asp-validation-for="AddressLine1" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="AddressLine2"></label><br />
<input asp-for="AddressLine2" class="form-control" maxlength="100" />
<span asp-validation-for="AddressLine2" class="text-danger"></span>
</div>
</div>
</div>
<div class="box">
<div class="form-group pull-right">
<button type="submit" class="btn btn-primary" value="save"> Save</button>
</div>
</div>
Is there something I am doing wrong? I have verified that the debug control goes to the Get method.There's alos no on load scripts which are doing any sort of validation.
1.Your get method contains the model parameter, when the request hit the method it will judge the ModelState by default. And when you hit the get method by your shared <a>, it send request without any data, so the ModelState is invalid.
2.Default Tag helper displays ModelState's value not Model.
In conclusion, you will render the ModelState error although it is a get method.
Two ways you can resolve this problem. The first way is that you can add ModelState.Clear() before you return View:
public ActionResult Details(StudentInfo model)
{
ModelState.Clear(); //add this....
helper.StudentInfo(ref model);
return View(model);
}
The second way is do not add the model as parameter:
public ActionResult Details()
{
var model = new StudentInfo();
helper.StudentInfo(ref model);
return View(model);
}

ASP.NET Core: I want to have access to the list of checkboxes (value) from my view on my controller's method

In my view I have markup similar to this:
#model C.Models.CM
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div class="form-group">
<label asp-for="Date" class="control-label"></label>
<input asp-for="Date" class="form-control" />
<span asp-validation-for="Date" class="text-danger"></span>
</div>
<div class="row">
<select data-placeholder="Select Item" asp-for="IdItem" class="form-control" asp-items="ViewBag.Items"></select>
</div>
<div class="form-group">
<input id="cboAll" type="checkbox" value="CheckAll / unCheck" /> All<br />
#foreach (var cdos in ViewBag.Modelon.Cdos)
{
<input id=#cdos.Id type="checkbox" value=#cdos.Id class="w3-check" />#cdos.Name<br />
}
</div>
<div class="form-group">
<input id="cboAll" type="checkbox" value="CheckAll / unCheck" /> All<br />
#foreach (var ctres in ViewBag.Modelon.Ctres)
{
<input id=#ctres.Id type="checkbox" value=#ctres.Id class="w3-check" />#ctres.Name<br />
}
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
The important thing to understand here is that, this markup generates a number N of CheckBox which depend on data inserted in the database, in addition to other attached information in the view.
The view looks like this:
My View
So, as you see the number of CheckBox goes from 1 to N.
My problem is the following, I can't understand how to obtain the CheckBox group data in my controller. I don't even know if this information is actually being sent to the controller.
I have the following code in my controller:
public async Task<IActionResult> Create(List<string> slct)
{
System.Diagnostics.Debug.WriteLine("test");
foreach (string value in slct)
{
System.Diagnostics.Debug.WriteLine(value);
};
System.Diagnostics.Debug.WriteLine("test");
return RedirectToAction(nameof(Index));
}
I would like that my code does certain things depending on the information that comes from the checkboxes, right now I was trying to see if all the data from the view was being sent as a select list, but that isn't the case because this code doesn't print anything in the debug screen except for the "test".
I've done my research, and people recommended the following links to learn how to load related data in the controller.
https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/read-related-data?view=aspnetcore-5.0
https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/update-related-data?view=aspnetcore-5.0
The problem is that no matter how much I read the tutorials, I can't understand them or solve how to apply them to my case, because they work with a much more complex example, and the fact that the code I need to use is of the type
await _context.Model.Include(a => a.Thing1)
.Include(b => b.Thing2)
.ThenInclude(c => c.Whatiscwhatisbwat??)
certainly doesn't help (the writing of that code is very confusing for me and I am having problems understanding what it does).
So, ok someone could help me with an explanation somewhat simpler than the one from the tutorials, to solve this? In the method that I mention from the controller, I want to have access to the two groups of checkboxes from the view and their selected values, in any format (like a List, Array, etc), I know that I must implement an include code but I don't know how to do it, or if there is a simpler solution.
I want to have access to the two groups of checkboxes from the view and their selected values
Please note that you do not specify name attribute for these checkbox(es) input, which would cause that all checked values would not be posted to server-side.
To achieve your above requirement, you can modify the code like below.
Specify name attribute for checkbox(es)
<div class="form-group">
<input id="cboAll" type="checkbox" value="CheckAll / unCheck" /> All<br />
#foreach (var cdos in ViewBag.Modelon.Cdos)
{
<input id=#cdos.Id type="checkbox" name="selectedCdos" value=#cdos.Id class="w3-check" />#cdos.Name<br />
}
</div>
<div class="form-group">
<input id="cboAll" type="checkbox" value="CheckAll / unCheck" /> All<br />
#foreach (var ctres in ViewBag.Modelon.Ctres)
{
<input id=#ctres.Id type="checkbox" name="selectedCtres" value=#ctres.Id class="w3-check" />#ctres.Name<br />
}
</div>
Action method that accepts checked values as parameter
public async Task<IActionResult> Create(ModelOfCheckedVals slct)
{
//...
//code logic here
//...
Model class ModelOfCheckedVals
public class ModelOfCheckedVals
{
public List<int> selectedCdos { get; set; }
public List<int> selectedCtres { get; set; }
}
Test Result

ASP.NET Core Model Binding: Using Dropdown List as Label

I am making an ASP.NET Core Mvc web app and am working on a search form. In the form, a user can be looked up by first name, last name, zip, and either ID, email, or phone. Whether a user is inputting ID, email, or phone is determined by a drop down list. I want to bind this to the User model I have but am not sure how to do it dynamically with the dropdown list. I am able to bind first name, last name, and zip just fine since they are not dynamic fields. Code for what I have so far for the form is below:
<form asp-action="Search">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label for="sel1">Search By:</label>
#* The dropdown menu to choose input type *#
<select class="form-control" id="sel1">
<option>ID</option>
<option>Email</option>
<option>Phone</option>
</select>
</div>
#* Where users would input information for the dropdown field *#
<div class="form-group">
<label for="id">Value:</label>
<input type="text" class="form-control clearable" id="id" Placeholder="0123456789">
</div>
<div class="form-group">
<label asp-for="FirstName">First Name:</label>
<input asp-for="FirstName" type="text" class="form-control clearable" id="firstName" Placeholder="Jane">
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LastName">Last Name:</label>
<input asp-for="LastName" type="text" class="form-control clearable" id="lastName" Placeholder="Doe">
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Zip">Zip Code:</label>
<input asp-for="Zip" type="text" class="form-control clearable" id="zipCode" Placeholder="55555">
<span asp-validation-for="Zip" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Search" class="btn btn-default" id="search" />
</div>
</form>
Then the code where the model is bound on the Search function:
public async Task<IActionResult> Search([Bind("FirstName, LastName, Zip")] Consumer consumer)
{
// Code....
}
Is there a way to dynamically bind the input for the text input with id="id" based on the dropdown menu selection? Thanks in advance.
There's two options:
Render all the fields to the page (first, last, zip, etc.), and then use JavaScript to hide/show those fields based on the selection in the drop down list. For example, if you select "First Name", then show the FirstName input and hide the others. The user then enters their keywords in that input, and when they post, it will bind to FirstName naturally.
Post the value of the drop down and a generic text input. In your action, you can then simply switch on the value of the drop down and query the right property:
IQueryable<Foo> query = db.Foos;
switch (model.MyDropDownSelection)
{
case "FirstName":
query = query.Where(x => x.FirstName.Contains(keyword));
break;
// etc.
}

Form fields from the ASP.NET View appear NULL in the Controller

The form fields do not return the value of the form even thought the asp-controller and asp-action is stated.
The form does go to the right controller function and returns the right view, however, it does the form object is NULL.
#using ActionAugerMVC.Models
#model Tuple<IEnumerable<Cities>,Content,IEnumerable<Content>,Quote>
#addTagHelper "*,Microsoft.AspNetCore.Mvc.TagHelpers"
<div class="sidebar__item">
<p class="subheading">Instant Quote Request</p>
<form class="register__form" role="form" asp-controller="Plumbing" asp-action="QuoteForm" method="post">
<div class="text-danger" asp-validation-summary="All"></div>
<div class="form-group">
<label class="sr-only">Full Name </label>
<input asp-for="#Model.Item4.FullName" type="text" class="form-control" placeholder="Full name">
</div>
<div class="form-group">
<label class="sr-only">Your phone</label>
<input asp-for="#Model.Item4.Phone" type="tel" class="form-control" placeholder="Your phone">
<span asp-validation-for="#Model.Item4.Phone" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">E-mail</label>
<input asp-for="#Model.Item4.Email" type="email" class="form-control" placeholder="E-mail">
<span asp-validation-for="#Model.Item4.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">Your Message</label>
<input asp-for="#Model.Item4.Message" type="text" class="form-control" placeholder="Your Message">
</div>
<input type="submit" value="Get a Quote Now" class="btn btn-accent btn-block">
</form>
</div> <!-- .sidebar__item -->
And the Controller looks like this, with the Quote object being null.
The hard coded, values appear correctly in the view, but the Quote object returned by the form is null.
[HttpPost]
public IActionResult QuoteForm(Quote quote)
{
if (ModelState.IsValid)
{
/* quote.FullName = "Umar Aftab";
quote.Email = "test#email.com";
quote.City = "Calgary";
quote.Message = "Test Message";
quote.Phone = "6474543769";
*/
}
return View(quote);
}
The issue is your use of a Tuple as your view's model combined with asp-for. For example, with something like:
<input asp-for="#Model.Item4.FullName" type="text" class="form-control" placeholder="Full name">
The name of the input is going to end up as Item4.FullName. However, your action accepts only Quote, which means the modelbinder needs the input to be named just FullName in order to bind it properly. You either need to accept the same model the view uses (though I've never tried posting a Tuple so not sure if that will even work), or you can use a partial view to work around the issue.
Essentially, you just would need to move all the fields related to just Quote to a partial view. Then, in this view, you can include them via:
#Html.Partial("_QuoteFields", Model.Item4)
That should be enough psych Razor out enough to just name the fields like FullName instead of Item4.FullName. If it's not, then you may need to reset the HtmlFieldPrefix, via:
#Html.Partial("_QuoteFields, Model.Item4, new ViewDataDictionary(ViewData) { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "" } })
The model on your view is different than the model you're trying to bind it to in the controller. You're not going to get the key/value pairs to match up
Put your razor in a partial view with Quote as the model and try that.
_QuoteForm.cshtml
#model Quote
<div class="form-group">
<label class="sr-only">Full Name </label>
<input asp-for="FullName" type="text" class="form-control" placeholder="Full name">
</div>
<div class="form-group">
<label class="sr-only">Your phone</label>
<input asp-for="Phone" type="tel" class="form-control" placeholder="Your phone">
<span asp-validation-for="Phone" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">E-mail</label>
<input asp-for="Email" type="email" class="form-control" placeholder="E-mail">
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">Your Message</label>
<input asp-for="Message" type="text" class="form-control" placeholder="Your Message">
</div>
OriginalView.cshtml
using ActionAugerMVC.Models
#model Tuple<IEnumerable<Cities>,Content,IEnumerable<Content>,Quote>
#addTagHelper "*,Microsoft.AspNetCore.Mvc.TagHelpers"
<div class="sidebar__item">
<p class="subheading">Instant Quote Request</p>
<form class="register__form" role="form" asp-controller="Plumbing" asp-action="QuoteForm" method="post">
<div class="text-danger" asp-validation-summary="All"></div>
#Html.Partial("_QuoteForm", Model.Item4)
<input type="submit" value="Get a Quote Now" class="btn btn-accent btn-block">
</form>
</div> <!-- .sidebar__item -->

mvc4 receive form in a controller

i have a form in html and i want to submit it to a controler
what i have tried
#using (Html.BeginForm("RegisterApartmentOwner", "Home", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<p>
<label>First Name</label>
<input type="text" placeholder="Enter your first Name" name="firstName" />
<span class="errorMessage"></span>
</p>
<p>
<label>Last Name</label>
<input type="text" placeholder="Enter your last Name" />
<span class="errorMessage"></span>
</p>
<p>
<label>Password</label>
<input type="text" placeholder="Enter your password" name="Password"/>
<span class="errorMessage"></span>
</p>
<p>
<label>Password Again</label>
<input type="text" placeholder="Enter your password again" name="Password2"/>
<span class="errorMessage"></span>
</p>
<p>
<label>Mobile Number</label>
<input type="text" placeholder="Enter your mobile number" />
<span class="errorMessage"></span>
</p>
<p>
<input type="submit" value="Register" class="submit"/>
</p>
}
</div>
and in the controller i receive the submit in this function
public String RegisterTenant() {
return "done";
}
i can see the done message, however, i want to receive the values of the input that i used in the form, how please?
i just to know what to receive the form in the controller
You could accept the formcollection (as in: FormCollection collection) as a parameter in your post action, or, better yet, create a view model, send that to the view and post it to the controller. You'd have to set it as a parameter of your http post action course.
Example:
[HttpPost]
public String RegisterTenant(FormCollection collection) {
// give all your html elements you want to read values out of an Id, like 'Password'
var password = collection["Password"];
// do something with your data
return "done";
}
Or (better!):
View model:
public class HomeViewModel
{
[Required]
public string UserName {get;set;}
}
View (on top):
#model Namespace.HomeViewModel
View (in your form):
#Html.TextBoxFor(m => m.UserName)
Controller:
[HttpPost]
public String RegisterTenant(HomeViewModel model)
{
var userName = model.UserName;
// do something
}
But you should really do some investigation into MVC: Views, Models & Controllers and what they do. It is really better to create a typesafe view model and work with that.

Categories

Resources