Action in controller received empty model from Html.BeginForm - ASP.NET MVC - asp.net-mvc

I have stucked for 3 days. There is nowhere I had been looking for this problem. When I submit the form, Controller action method doesnt get the model.
My base view Login.cshtml
#{
string durum = ViewBag.Style;
switch (durum)
{
case "Login":
Html.RenderAction("_Login", "Dashboard");
break;
case "LostPassword":
Html.RenderAction("_LostPassword", "Dashboard");
break;
case "RegisterForm":
Html.RenderAction("_RegisterForm", "Dashboard");
break;
default:
Html.RenderAction("_Login", "Dashboard");
break;
}
}
One of my partial view _LostPassword.cshtml
#model HaberSitesi._Entities.Kullanici
#using (Html.BeginForm("LostPassword", "Dashboard", FormMethod.Post, new { #class = "forget-form", #style = "display:block" }))
{
if (TempData["ForgotPassword"] != null)
{
<div class="alert alert-warning ">
<button class="close" data-close="alert"></button>
<span>#TempData["ForgotPassword"]</span>
</div>
}
<h3>Şifrenizi mi unuttunuz ?</h3>
<p> Şifrenizi almak için lütfen E-Posta adresinizi giriniz. </p>
<div class="form-group">
<div class="input-icon">
<i class="fa fa-envelope"></i>
#Html.TextBoxFor(x => x.EPosta, new { #class = "form-control placeholder-no-fix", #type = "email", #autocomplete = "off", #placeholder = "Eposta", Name = "email" })
#Html.ValidationMessageFor(x => x.EPosta)
</div>
</div>
<div class="form-actions">
#Html.ActionLink("Geri Dön", "Login", "Dashboard", new { }, new { #type = "button", #id = "back-btn", #class = "btn grey-salsa btn-outline" })
<button type="submit" class="btn green pull-right"> Gönder </button>
</div>
}
And the action in controller DashboardController.cs
public ActionResult LostPassword()
{
VeriTransfer();
return View("Login");
}
[HttpPost]
public ActionResult LostPassword(Kullanici kullanici)
{
string kullaniciEposta = kullanici.EPosta;
Kullanici user = _kullaniciBll.Get(kullaniciEposta);
if (user != null)
{
TempData["ForgotPassword"] = "Şifreniz e-posta adresinize gönderildi.";
}
else
{
TempData["ForgotPassword"] = "Kayıtlarımızda e-posta adresiniz bulunamadı";
}
VeriTransfer();
return View("Login");
}
When I click submit button, I cant get any data (Kullanici kullanici) in controller. Every property comes null or default data value from model.
Note: Maybe my codes could have some other mistakes which are irrelevant with my problem. I just wonder why I get empty model. Thanks at least you have read my problem.

Your property is called EPosta but you changed the name of it to Name="email".So when the POST action happens it sends a property called email to the controller action and your Kullanici object expects a property called EPosta
Both of these will fix your problem:
Change Name="email" to Name="EPosta" or
Remove Name="email" completely
But like Stephen said it's better to remove it completely,because if you rename your property to EPosta2 in future and forget to change the name to Name="EPosta2" your POST will no longer work

Related

How can i pass multiple radio button values to controller in ASP.NET MVC?

I've a model that contains 3 tables in my view.
public class InExam
{
public AutoTests TheTest { get; set; }
public List<InTest> TheQuestions { get; set; }
public IEnumerable<Result> SingleQuee { get; set; }
}
First one made to get the detailed page, like "admin/AutoTests/id"
Second one made to get a list of questions linked to the page
Third one is to save radio button strings to post it back into the controller
my plan is to get (say) 20 questions that are linked with the detailed page, Adding 4 radio buttons for each question, and post back every selected button to the controller.
my view form :
#using (Html.BeginForm("Test", "Exams", new { id = Model.TheTest.id }, FormMethod.Post))
{
foreach (var item in Model.TheQuestions)
{
Kafo.Models.Result singleQuee = Model.SingleQuee.Where(x => x.Question == item.Question).FirstOrDefault();
<div class="container" style="padding-top:50px;direction:rtl;">
<h4 style="text-align:right;font-weight:bold;">#item.Question</h4>
<div class="container">
<div class="row" style="direction:rtl;">
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "1" })
<h5 style="padding-top:3px;padding-right:8px;">#item.RightAnswer</h5>
</div>
</div>
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "2" })
<h5 style="padding-top:3px;padding-right:8px;">#item.Answer2</h5>
</div>
</div>
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "3" })
<h5 style="padding-top:3px;padding-right:8px;">#item.Answer3</h5>
</div>
</div>
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "4" })
<h5 style="padding-top:3px;padding-right:8px;">#item.Answer4</h5>
</div>
</div>
#Html.HiddenFor(m => singleQuee.Question)
</div>
</div>
</div>
}
<button class="btn botton" type="submit" onclick="return confirm('');">END</button>
}
i used this line "Kafo.Models.Result singleQuee = Model.SingleQuee.Where(x => x.Question == item.Question).FirstOrDefault();" in my view because i can't use tuple foreach ( C# ver. 5 )
This is my controller code :
[HttpGet]public ActionResult Test(int? id)
{
using (KafoEntities db = new KafoEntities())
{
InExam model = new InExam();
model.TheTest = db.AutoTests.Where(x => x.id == id).FirstOrDefault();
model.TheQuestions = db.InTest.Where(x => x.UserEmail == currentUser.Email && x.ExamId == model.TheTest.id).OrderByDescending(x => x.id).Take(Convert.ToInt32(model.TheTest.QuestionsNumber)).ToList();
model.SingleQuee = db.Result.ToList();
return View(model);
}
}
[HttpPost]
public ActionResult Test(int? id, List<Result> singleQuee)
{
using (KafoEntities db = new KafoEntities())
{
int result = 0;
foreach (Result item in singleQuee)
{
Result sets = db.Result.Where(x => x.id == item.id).FirstOrDefault();
sets.Question = item.Question;
db.SaveChanges();
var check = db.InTest.Where(x => x.Question == item.Question).FirstOrDefault();
if (check != null)
{
if (item.Question == "1")
{
result++;
}
}
}
return RedirectToAction("Results", "Exams", new { Controller = "Exams", Action = "Results", id = done.id });
}
}
I first save the new string that came from the radio button value into the result record, then i call it back in the if condition to check it's value
The problem here is i get a
Object reference not set to an instance of an object.
when i post the test, it means that the list is empty, so i need to know what makes the radio buttons not working,
Thanks.
If you want to bind a List of object in Mvc, you should name the controller like "ModelName[indx].PropertyName". In your case it should be "singleQuee[0].Question".
Code Sample
var Indx = 0;
foreach (var item in Model.TheQuestions)
{
.....
var radioName = $"singleQuee[{Indx}].Question";
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
<input type="radio" name="#radioName" value="1" />
<h5 style="padding-top:3px;padding-right:8px;">#item.RightAnswer</h5>
</div>
</div>
.....
}
Action Method

How to check if any model item is assigned a value in MVC?

I have a model which have properties.And, i want to check that if any model item has some value or not.Also,no property is set to mandatory or optional using data-annotations.If no property is assigned and any value then i should set some model error e.g "Please specify some search criteria."
#using (Html.BeginForm("GetAdvanceSearchData", "Home", FormMethod.Post)){
<div class="rTableCell" style="border:none !important">
#Html.TextBoxFor(m => m.MessageStatus, new { placeholder = Html.DisplayNameFor(n => n.MessageStatus), #class = "fieldtextbox", #style = "height: 25px !important" })
#Html.ValidationMessageFor(m => m.MessageStatus)
</div>
<div class="rTableCell" style="border:none !important">
#Html.TextBoxFor(m => m.RequestType, new { placeholder = Html.DisplayNameFor(n => n.RequestType), #class = "fieldtextbox", #style = "height: 25px !important" })
#Html.ValidationMessageFor(m => m.RequestType)
</div>
<div class="rTableCell" style="border:none !important">
</div>
<div class="rTableCell" style="border:none !important">
<p class="submit">
<button type="submit" name="submit">
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</button>
</p>
</div>
}
These are only few properties for the model.
In action method GetAdvanceSearchData you can do your own validity checks, in addition to validation attributes, or instead of them.
If you add an entry to ModelState then ModelState.IsValid will become false, and the added entry will show in the output of Html.ValidationMessageFor(...) or Html.ValidationSummary().
Example:
[HttpPost]
public ActionResult GetAdvanceSearchData(YourModel vm)
{
if (vm == null || (string.IsNullOrEmpty(vm.MessageStatus) && string.IsNullOrEmpty(vm.RequestType)))
{
ModelState.AddModelError("", "Please specify some search criteria")
// Using "" as Key will only show when you use #Html.ValidationSummary().
// Using "myErr" as Key will show when you use #Html.ValidationMessage("myErr").
// Using a property name as Key will show it next to the property if you use #Html.ValidationMessageFor(m => m.property).
}
if (ModelState.IsValid)
{
var results = ...
return View("ResultsView", results);
}
else
{
return View(vm);
}
}

Ajax BeginForm POST using MVC and Razor

I keep getting a 404 and searching all over SO and cannot target the issue here. The form is the result of a render action and appears on the home page (home controller). However, I want it to post a different controller action and it keeps giving me a 404. I have included all the correct script for unobtrusive javascript as well as the necessary web.config settings and I'm unable to come across a similar problem from my research.
This is the partial with the form that is being rendered:
#model AFS.Models.SearchLocationModel
<div class="site-search-module">
<div class="site-search-module-inside">
#using (Ajax.BeginForm("SearchCare", "LevelOfCare", null, new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "searchDiv" }, new { #class = "search-form", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="row">
<div class="col-md-12">
<h5>Select a category</h5>
#Html.DropDownListFor(x => x.Level, Model.LevelSelectList, new { #class = "form-control input-lg selectpicker" })
</div>
<div class="col-md-12">
<h5>Enter location</h5>
<input type="text" id="Location" name="Location" class="form-control input-lg selectpicker" placeholder="City, State OR Zip Code" required />
</div>
<div class="col-md-12"> <button type="submit" class="btn btn-primary btn-block btn-lg search"><i class="fa fa-search"></i> Search</button> </div>
</div>
}
</div>
The controller action is:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SearchCare(SearchLocationModel model)
{
if (ModelState.IsValid)
{
SearchLocationModel geocodeModel = Geocode(new SearchLocationModel() { Level = model.Level, Location = model.Location });
if (geocodeModel.Status == "OK")
{
Session["level"] = model.Level;
return RedirectToRoute("LevelCity", new { level = model.Level, state = geocodeModel.State, city = geocodeModel.City, latitude = geocodeModel.Latitude, longitude = geocodeModel.Longitude });
}
else
{
ModelState.AddModelError(string.Empty, "Please enter City, State OR Zip Code.");
return RedirectToAction("SearchWidget", "Home");
}
}
else
{
return RedirectToAction("SearchError");
}
}

MVC 5 Ajax.BeginForm only works the first time

I've been struggling for a while now with the Ajax.BeginForm.
So, what I want to achieve is:
Clicking a button that will open a Modal Popup with a Partial View inside.
When I close the Modal Popup by pressing the Save button the information will be reloaded on the target control id by call an action on the controller.
What is happening is that the first time I do this, everything seems to work as intended. However as soon as I try to add something else, it does not work anymore.
Here goes the code.
Heres the code on the view that is being loaded inside the Modal Popup
#model GEMS.Models.ViewModels.AddressVM
#{
string controllerName = ViewContext.RouteData.Values["controller"].ToString();
string actionName = ViewContext.RouteData.Values["action"].ToString();
}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">#HTMLHelper.TranslateCRUDTitles(controllerName, actionName)</h4>
</div>
#using (Ajax.BeginForm(new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, OnSuccess = "ShowSuccess", OnFailure = "ShowFailure" }))
{
#Html.AntiForgeryToken()
<div class="modal-body">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#foreach (System.Reflection.PropertyInfo prop in Model.GetDisplayProps())
{
switch (prop.Name)
{
case "NewAddressTypeName":
break;
case "AddressType":
<div class="form-group">
#Html.Label(prop.Name)
#Html.DropDownList("AddressTypeID", null, htmlAttributes: new { #class = "form-control" }).DisableIf(() => actionName == "Delete")
#Html.ValidationMessage(prop.Name, new { #class = "text-danger" })
</div>
break;
case "Country":
<div class="form-group">
#Html.Label(prop.Name)
#Html.DropDownList("CountryID", null, htmlAttributes: new { #class = "form-control" }).DisableIf(() => actionName == "Delete")
#Html.ValidationMessage(prop.Name, new { #class = "text-danger" })
</div>
break;
case "IsDefault":
<div class="form-group">
<label class="checkbox-inline">
#Html.Editor(prop.Name, new { htmlAttributes = new { #class = "grey" } }).DisableIf(() => actionName == "Delete")
#Html.Label(prop.Name)
</label>
#Html.ValidationMessage(prop.Name, new { #class = "text-danger" })
</div>
break;
case "SameAsID":
if (ViewBag.SameAsID != null)
{
<div class="form-group">
#Html.Label(prop.Name)
#Html.DropDownList(prop.Name, null, htmlAttributes: new { #class = "form-control" }).DisableIf(() => actionName == "Delete")
#Html.ValidationMessage(prop.Name, new { #class = "text-danger" })
</div>
}
break;
default:
<div class="form-group">
#Html.Label(prop.Name)
#Html.Editor(prop.Name, new { htmlAttributes = new { #class = "form-control" } }).DisableIf(() => actionName == "Delete")
#Html.ValidationMessage(prop.Name, new { #class = "text-danger" })
</div>
break;
}
}
#foreach (System.Reflection.PropertyInfo prop in Model.GetHiddenProps())
{
<input id="#prop.Name" name="#prop.Name" type="hidden" value="#Model.GetPropValue(prop.Name)">
}
</div>
<div class="modal-footer">
#if (actionName == "Delete")
{
<p>
#Resources.ConfirmAddressDelete
</p>
}
<button class="btn btn-yellow" type="button" data-dismiss="modal">
#Resources.Cancel <i class="fa fa-arrow-circle-left"></i>
</button>
#switch (actionName)
{
case "Create":
case "Edit":
<button class="btn btn-success" type="submit" value="Save">
#Resources.Save <i class="fa fa-save"></i>
</button>
break;
case "Delete":
<button class="btn btn-red" type="submit" value="Delete">
#Resources.Delete <i class="fa fa-times"></i>
</button>
break;
}
</div>
}
Here's the controller relevant actions:
public ActionResult Index(List<AddressVM> addressVMList)
{
addressVMList = addressVMList ?? (List<AddressVM>)TempData["AddressVMList"];
TempData["AddressVMList"] = addressVMList;
TempData.Keep("AddressVMList");
return PartialView("_Index", addressVMList);
}
public ActionResult Create()
{
TempData.Keep("AddressVMList");
ViewBag.AddressTypeID = new SelectList(AddressType.GetList(), "ID", "Name");
ViewBag.CountryID = new SelectList(Country.GetList(), "ID", "NiceName");
List<AddressVM> addressVMList = (List<AddressVM>)TempData["AddressVMList"];
return PartialView("_CreateEditDelete", new AddressVM());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(AddressVM addressVM)
{
if (ModelState.IsValid)
{
//Create a fake ID in order to be able to edit and manipulate the address before it is actually saved
List<AddressVM> addressVMList = (List<AddressVM>)TempData["AddressVMList"];
addressVM.Id = (addressVMList.Count + 1) * -1;
addressVMList.Add(addressVM);
if (addressVM.IsDefault) ListedPropVM.SetDefault(addressVMList.Cast<ListedPropVM>().ToList(), addressVM.Id);
TempData.Keep("AddressVMList");
string url = Url.Action("Index", "Addresses", null);
return Json(new { success = true, url = url, method = "replaceTargetAddresses" });
}
// return PartialView("_CreateEditDelete", addressVM);
return RedirectToAction("Create");
}
And finally the script that is run when OnSuccess:
function ShowSuccess(data) {
if (data.success) {
$('#defaultModal').modal('hide');
$('#' + data.method).load(data.url);
}
}
function ShowFailure(data) {
alert('Problem occured');
}
Thanks in advance for your help and time.
Well I solved the problem by adding the following to the script on the partial view:
<script type="text/javascript">
**$(document).ready(function () {
$.ajaxSetup({ cache: false });
});**
function ShowSuccess(data) {
if (data.success) {
$('#defaultModal').modal('hide');
$('#' + data.method).load(data.url);
}
}
function ShowFailure(data) {
$('#defaultModalContent').html(result);
}
</script>
Hope this helps someone else.

MVC Form Losing Values During Server Side Validation

I am migrating an existing site from WebForms to MVC 5.
I have a Contact Us page that has client-side validation for checking if the fields are completed, etc. However, I am using BotDetect CAPTCHA which has server-side validation to check if the CAPTCHA was completed correctly.
If I enter the correct CAPTCHA, all works as expected -- an email is sent and all the form fields are represented in the email.
If I enter the wrong CAPTCHA, I should be returned to the form, an error message will be displayed for the invalid CAPTCHA but all the other fields should be still filled in.
However, this isn't happening. The form field is lost. I am guessing this is because the Model is getting regenerated. What I haven't figured out is how to get my ActionResult to just abandon doing any actions and leave the form contents in place.
My view:
#using BotDetect.Web.UI.Mvc;
#model Framework.Models.FrameworkModel
#section Styles {
<link href="#BotDetect.Web.CaptchaUrls.Absolute.LayoutStyleSheetUrl" rel="stylesheet" type="text/css" />
}
<h1>#Html.Raw(Model.Page.Heading)</h1>
<div class="main-container">
#if (string.IsNullOrWhiteSpace(ViewBag.Status))
{
#Html.Raw(Model.Page.Body)
<br />
<fieldset id="ContactFields" class="contact-fields">
<ol>
<li>
<label id="FullNameLabel" labelfor="FullName">#Resources.Contact.FullNameLabel</label>
#Html.TextBoxFor(model => model.Contact.FullName, new { #id = "FullName", #Name = "FullName", #class = "standard-textbox", #autocompletetype = "DisplayName", #data_validation_required = Resources.Contact.FullNameValidationErrorMessage})
</li>
<li>
<label id="EmailLabel" labelfor="Email">#Resources.Contact.EmailLabel</label>
#Html.TextBoxFor(model => model.Contact.Email, new { #id = "Email", #Name = "Email", #class = "standard-textbox", #autocompletetype = "Email", #data_validation_required = Resources.Contact.EmailValidationErrorMessage, #data_validation_format = Resources.Contact.EmailValidationErrorMessageFormat })
</li>
<li>
<label id="SubjectLabel" labelfor="Subject">#Resources.Contact.SubjectLabel</label>
#Html.TextBoxFor(model => model.Contact.Subject, new { #id = "Subject", #Name = "Subject", #class = "standard-textbox", #data_validation_required = Resources.Contact.SubjectValidationErrorMessage })
</li>
<li>
<label id="MessageLabel" labelfor="Message">#Resources.Contact.MessageLabel</label>
#Html.TextAreaFor(model => model.Contact.Message, new { #id = "Message", #Name = "Message", #class = "multiline-textbox", #rows = 5, #data_validation_required = Resources.Contact.MessageValidationErrorMessage })
</li>
<li>
<div class="captcha-control">
<br />
#{ MvcCaptcha captcha = Model.CaptchaHelper.GenerateCaptcha(); }
#Html.Captcha(captcha)
<br />
#Html.TextBox("CaptchaCode", "", new { #id = "CaptchaCode", #Name = "CaptchaCode", #class = "captcha-code short-textbox", #data_validation_required = Resources.Captcha.CaptchaValidationErrorMessage })
#Html.ValidationMessage("CaptchaCode")
</div>
<br />
<button id="SendButton" type="submit" class="send-button">#Resources.Contact.SendButton</button>
</ol>
</fieldset>
}
else
{
<span class="alert">#Html.Raw(ViewBag.Status)</span>
}
</div>
#section Scripts {
#Scripts.RenderFormat("<script type=\"text/javascript\" src=\"{0}\" defer=\"defer\"></script>", "~/bundles/scripts/contact")
}
Part of my controller (removed calls to irrelevant actions):
using Framework.App_Code.ViewRendering;
using Framework.Models;
using System.Web.Mvc;
using BotDetect.Web.UI.Mvc;
namespace Framework.Controllers
{
public class PagesController : AsyncController
{
[HttpGet]
[ActionName("Contact")]
public ActionResult Contact()
{
Contact viewRendering = new Contact();
return View(viewRendering.GenerateModel());
}
[HttpPost]
[ActionName("Contact")]
[AllowAnonymous]
[CaptchaValidation("CaptchaCode", "Captcha")]
public ActionResult ContactPost(ContactModel contactModel, bool captchaValid)
{
Contact viewRendering = new Contact();
if (ModelState.IsValid)
{
contactModel.IPAddress = Request.ServerVariables["REMOTE_ADDR"].Trim();
ViewBag.Status = viewRendering.SendMail(contactModel);
}
MvcCaptcha.ResetCaptcha("Captcha");
return View(viewRendering.GenerateModel());
}
}
}
When you return back to the view in the invalid case, pass the model back to have it re-displayed (i.e. when !ModelState.IsValid do this...)
return View(contactModel); // this is the one that was submitted

Resources