MVC4 - Model not been passed to controller for action - c#

I've got two models.
Model A for example contains basic get set for atrributes (i.e)
[Required]
[StringLength(100)]
[Display(Name = "Comment: ")]
public string Comment { get; set; }
public bool IsSuccess { get; set; }
Model two uses attributes in modal a, i.e
public ModelA Deposit { get; set; }
public ModelA Withdrawal { get; set; }
public ModelA Transfer { get; set; }
In my View all I am doing is using 3 forms in one page with very similar fields.
For same reason Withdrawal and transfer work with no problems. The code is almost identical in all 3
However when I am doing deposit, the ActionResult in the post is not been passed on the model.
public ActionResult Index()
{
SetViewBagAccounts();
var model = new ModelB {};
return View(model);
}
[HttpGet]
public ActionResult Deposit()
{
return View();
}
[HttpPost]
public ActionResult Deposit(ModelB model)
{
int acct = Convert.ToInt32(Request.Form["Accounts"]);
var comment = model.Deposit.Comment;// This causes **NullReferenceException**
}
The error I am getting in http post is NullReferenceExcption.
When I debug, the model being passed to the action method, Deposit, is all empty.
BELOW IS A SAMPLE OF THE VIEW
#model Login.Models.ModelB
#{
ViewBag.Title = "ATM";
}
<h2>ATM</h2>
<div id="leftpanel" style="position:absolute;left:0;width:33%;">
#using (Html.BeginForm("Deposit", "ATM", FormMethod.Post, new {}))
{
<div>
<fieldset>
<legend>Deposit Money</legend>
<div>#Html.LabelFor(u=>u.Deposit.AccountNumber1)</div>
<div>#Html.DropDownList("Accounts", "-- Select Account --")
</div>
<div>#Html.LabelFor(u=>u.Deposit.Amount)</div>
<div>#Html.TextBoxFor(u=>u.Deposit,new {style = "width:150px"})
#Html.ValidationMessageFor(u=>u.Deposit.Amount)
</div>
<div>#Html.LabelFor(u=>u.Deposit.Comment)</div>
<div>#Html.TextAreaFor(u=>u.Deposit.Comment,new {style = "width:250px"})
#Html.ValidationMessageFor(u=>u.Deposit.Comment)
</div>
<input type="submit" value ="Submit" style="width:31%;"/>
<input type="reset" value ="Clear" style="width:31%;"/>
</fieldset>
</div>
}
The div for deposit is pretty much copied again for withdrawal and transfer, only changed bit is :
#using (Html.BeginForm("Withdrawal", "ATM", FormMethod.Post, new {}))
#using (Html.BeginForm("Transfer", "ATM", FormMethod.Post, new {}))

Related

Add an object from a View (Passing from View to Controller)

I'm working in a C# project. In my ReglasDispositivos view there are three diferent actions which a client can do: add a device, update a device and delete once. The controller calls ReglasDispositivos() (get) view passing a ClienteReglasDispositivos model. Lets go, for example, to adding a device. How can i post the info that the client is posting?
If my view only have one action, I know that I have to add in the controller [HttpPost] and [HttpGet] ReglasDispositivos() method. But when a view has three diferentes actions?
ClientController:
[HttpGet]
public ActionResult ReglasDispositivos()
{
ClienteReglasDispositivos model = new ClienteReglasDispositivos();
return View(model);
}
ReglasDispositivos view (Adding a device parte) (Im not sure about that BeginForm):
#model SistemaGestion.Models.ClienteReglasDispositivos
...
<div class="view-tables">
<div id="myAdd" class="div-table">
#using (Html.BeginForm("AgregarDispositivo", "Client", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<fieldset class="fieldset-box">
<div class="editor-field">
#Html.TextBoxFor(model => model.NombreDispositivo, new { Class = "YourBackgroundClass", Placeholder = "Nombre del dispositivo" });
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.HorasDeUso, new { Class = "YourBackgroundClass", Placeholder = "KwPorHora" });
</div>
<div class="editor-field">
#Html.CheckBoxFor(model => model.EsInteligente, new { Class = "YourBackgroundClass" });
</div>
<input type="submit" class="submit-login" value="AGREGAR" />
</fieldset>
}
</div>
ClienteReglasDispositivos
public class ClienteReglasDispositivos
{
[Required]
public string NombreDispositivo { get; set; }
[Display(Name = "Es inteligente?")]
public bool EsInteligente { get; set; }
public double KwPorHora { get; set; }
public float HorasDeUso { get; set; }
public string Condicion { get; set; }
}
You can have multiple actions with identical name due to polymorphysm. Asp decide what action you call by [Http(XX)].
You can have
[HttpGet]
public ActionResult ReglasDispositivos()
{
ClienteReglasDispositivos model = new ClienteReglasDispositivos();
return View(model);
}
[HttpPost]
public ActionResult ReglasDispositivos([FromForm] ClienteReglasDispositivos model)
{
if(ModelState.IsValid(model)) {
//do something
}
return View(model);
}
Also you can call different action name and return same view
[HttpGet]
public ActionResult ReglasDispositivos()
{
ClienteReglasDispositivos model = new ClienteReglasDispositivos();
return View(model);
}
[HttpPost]
public ActionResult ReglasDispositivosPost([FromForm] ClienteReglasDispositivos model)
{
return View("ReglasDispositivos", model);
}
Read more

MVC 5 remote validation not fired

I'm trying to implement remote validation in MVC. I have read several tutos and questions already posted here, but there is no answer.
Controller :
public class GroupsController: Controller
{
[HttpPost]
public ActionResult TestRemoteValidation(string Name)
{
return Json(false);
}
}
View :
#using (Html.BeginForm("Index", "Defaults", FormMethod.Post))
{
#Html.TextBoxFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
<input type="submit" class="btn btn-primary" value="Enregistrer" />
}
And Model :
public class Group
{
[Key]
public int Id { get; set; }
[Display(Name = "Nom du Groupe")]
[Required]
[Remote("TestRemoteValidation", "Groups", HttpMethod = "POST", ErrorMessage = "Remote fired")]
//[CustomRemoteValidation("TestRemoteValidation", "Groups", AdditionalFields = "Id")]
public string Name { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUsers { get; set; }
}
Generated HTML Code:
<input data-val="true" data-val-remote="Remote fired" data-val-remote-additionalfields="*.Name" data-val-remote-type="POST" data-val-remote-url="/Groups/TestRemoteValidation" data-val-required="Le champ Nom du Groupe est requis." htmlAttributes="{ class = form-control }" id="Name" name="Name" type="text" value="" />
I'm using Metadata because it's an entity-->not the problem, I checked with an other ViewModel and it's the same.
[Required] and [StringLength(10)] are fired.
When I put a breakpoint in TestRemoteValidation, nothing happens.
For instance I'm able to perform the remote validation with a custom remote attribute class and Model.IsValid override, but I don't understand why this way doesn't work. Any idea?
Assuming Vehicule is the #model being used in the view
#model Vehicule
then the controller should expected that model
public class DefaultsController : Controller {
[HttpGet]
public ActionResult Index() {
var model = new Vehicule();
return View(mdoel);
}
[HttpPost]
public ActionResult Index(Vehicule model) {
if(ModelState.IsValid) {
//...do something
//..possible redirect
}
//if we get this far something is wrong with data
return View(model);
}
}
The model binder will take validation into account when binding the model from the request.
add
[AllowAnonymous]
to
[HttpPost]
public ActionResult TestRemoteValidation(string Name)
Please make sure that you have included below libraries and in correct order in your view
<script src="~/scripts/jquery.js"></script>
<script src="~/scripts/jquery.validate.js"></script>
<script src="~/scripts/jquery.validate.unobtrusive.js"></script>
these libraries are required for remote validation to work.

DropDownListFor always return null to controller

My ViewModel looks like this:
public class ProjectViewModel
{
public ICollection<Project> Projects { get; set; }
}
My controller:
[HttpPost]
[Route("ChooseProject")]
public ActionResult ChooseProject(Project projects)
{
return RedirectToAction("Index", "Application");
}
And finally my view:
#using ServicePortal.Web.Controllers
#model ServicePortal.Web.Models.ProjectViewModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Choose project";
}
<div class="pure-form pure-form-aligned">
#using (Html.BeginForm("ChooseProject", "Login", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="innerForm formgroup">
#Html.ValidationSummary(true, "", new { #class = "" })
#Html.DropDownListFor((model => model.Projects), new SelectList(Model.Projects,"ProjectKey", "ProjectName"))
<div class="row">
<button type="submit" class="button pull-right">Go on</button>,
</div>
</div>
}
</div>
The dropdownlist is populated with the correct values, but I would like to return either a Project or a string with ProjectKey to the controller. However, when I submit the form and check the value in the parameter in the controller, it is always null, both when I try to return a Project and when I try with string. I don't get any errors. What am I doing wrong?
Try this out:
public class ProjectViewModel
{
public string SelectedProjectKey { get; set; } // string may need to be int depending on what type ProjectKey is in your class
public ICollection<Project> Projects { get; set; }
}
In the view:
#Html.DropDownListFor((model => model.SelectedProjectKey), new SelectList(Model.Projects,"ProjectKey", "ProjectName"))
Your controller action:
public ActionResult ChooseProject(ProjectViewModel model)
This will get you the key of whatever project you selected in model.SelectedProjectKey and you can use that in your controller chooseproject action method to do whatever you intended.

mvc 4 Model is null

i'm using razor's listboxfor for the first time, but my Model is always null.
after reading similar posts and tryouts it still won't work.
Person.cshtml
#model SampleApp.Web.ViewModel.PersonViewModel
#{
ViewBag.Title = "Welcome";
}
<article>
<p>
Welcome to example page.
</p>
<p>
<div class="container">
//Post data works as expected, controllers create method write to db successfully
#using (Html.BeginForm("Create", "Person", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Personen</legend>
<div class="editor-label">
#* #Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Surrname)
</div>
</fielset>
</div>
<p>
<input type="submit" value="Create" />
</p>
}
//binding to Model fails, Model is null. Not be able to debug anything in controller action, it stops when "loading" the page
#using (Html.BeginForm("GetListBoxData", "Person"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.ListBoxFor(model => model.ListboxData, Model.ListboxData);
}
</div>
PersonController.cs
[AcceptVerbs(HttpVerbs.Get)]
[ValidateAntiForgeryToken]
public ActionResult GetListBoxData()
{
var data = new List<PersonViewModel>();
data.Add(new PersonViewModel{Name = "Test", Surrname="testsurrname", Age=30});
var viewModel = new PersonViewModel()
{
ListboxData = data.AsEnumerable().Select(s=> new SelectListItem{Value=s.Name ,Text = s.Surrname}),
};
return View(viewModel);
}
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult GetListBoxData(PersonViewModel persondata)
{
//TODO: handle values from View
return View(this);
}
[ValidateAntiForgeryToken]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Include = "Name, Surrname, Age")] PersonViewModel persondata)
{
try
{
PersonService personDataProvider = new PersonService();
personDataProvider.SavePerson(persondata);
return new RedirectResult("SomewhereToGo");
}
catch (DataException ex)
{
//TODO: Log
}
return View(this);
}
PersonViewModel
public class PersonViewModel
{
public int PersonId{ get; set; }
public int Age { get; set; }
public string Name { get; set; }
public string Surrname { get; set; }
public IEnumerable<SelectListItem> ListboxData { get; set; }
}
writing values from editFor to db works as expected without code for listboxfor.
after adding it to my html it should be filled from db on page loading, but I get a ReferenceNotSet Exception on page loading. Model.ListboxData is null, before GetListBoxData action is called.
Thanks a lot for your help!
Your form should submit the data via POST, not GET. And, you don't need to use enctype = "multipart/form-data", unless you want to upload files through your from.
You need two Index Actions in your Controller, one is for sending the data from your Controller to the View, and the other one is for getting the data back from the View, when the form is submitted (POST) to the server.
The first argument you pass to your ListBox (the expression) refers to the Property in your Model that the selected item from your ListBox will be stored in, which in this case is PersonId.
So, your View should look like this:
#model MVCApplication.Web.ViewModel.PersonViewModel
#using (Html.BeginForm("Index", "Person"))
{
#Html.ListBoxFor(model => model.PersonId, Model.ListBoxData)
<input type="submit" value="Save" />
}
Then, in your Controller, you'll have two Actions like this:
public ActionResult Index()
{
var viewModel = new PersonViewModel()
{
ListboxData = data.Select(s => new SelectListItem { Value = s.PersonId.ToString(), Text = s.PersonId.ToString() }).AsEnumerable();
};
return View(viewModel);
}
[HttpPost]
public ActionResult Index(PersonViewModel viewModel)
{
// code to save the data in the database or whatever you want to do with the data coming from the View
}
By the way, in your ViewModel, you don't have to define your ListBoxData property like that, just do this:
public class PersonViewModel
{
public int PersonId{ get; set; }
public IEnumerable<SelectListItem> ListBoxData { get; set; }
}

using strongly typed partial views inside another Strongly Typed view

I have NameModel and RegisterModel and SuperClass classes as below: -
Case 1: - Using SuperClass
public class SuperClass
{
public RegisterModel Register{ get; set; }
public NameModel NameInfo { get; set; }
}
public class NameModel
{
[Required]
public string FirstName { get; set; }
public string MiddleName { get; set; }
[Required]
public string LastName { get; set; }
}
public class RegisterModel
{
public NameModel NameInfo{ get; set; }
[Required]
public string UserName { get; set; }
[Required]
public string Password { get; set;}
}
MyNamePartial strongly typed View is as follows :-
#model MyNamespace.Models.NameModel
#{
Layout = null;
}
{
#Html.TextBoxFor(m=>m.FirstName,new { #id="firstName"} )
#Html.TextBoxFor(m=>m.MiddleName,new { #id="middleName"} )
#Html.TextBoxFor(m=>m.LastName,new { #id="lastName"} )
}
My Registration View is strongly typed of Register Model as follows :-
#model MyNamespace.Models.SuperClass
#{
Layout = "~/Views/_Layout.cshtml";
}
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "myForm" }))
{
<div id="form">
#Html.Partial("NameModel",Model.NameInfo)
#Html.TextBoxFor(m=>m.Register.UserName,new { #id="userName"})
#Html.TextBoxFor(m=>m.Register.Password,new { #id="password"})
<input type="submit" value="Register" id="btnRegister" />
</div>
}
Above approach gives object reference error.
Case 2: - Using HTML.Action and no SuperClass
Tried using #Html.Action("MyNamePartialView")instead of #Html.Partial("NameModel",Model.NameInfo),Then I use Controller Action method as below
My Registration View is strongly typed of Register Model as follows :-
#model MyNamespace.Models.RegisterModel
#{
Layout = "~/Views/_Layout.cshtml";
}
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "myForm" }))
{
<div id="form">
#Html.Action("MyNamePartialView")
#Html.TextBoxFor(m=>m.UserName,new { #id="userName"})
#Html.TextBoxFor(m=>m.Password,new { #id="password"})
<input type="submit" value="Register" id="btnRegister" />
</div>
}
Register Controller :-
public ActionResult MyNamePartialView()
{
return PartialView("MyNamePartial", new NameModel());
}
[HttpPost]
[AllowAnonymous]
public ActionResult Register(RegisterrModel model)
{
#ViewBag.sideMenuHeader = "Create an Account";
if (ModelState.IsValid)
{
//Perform Something
return View();
}
return View();
}
The above case doesnt bind the values entered on form. it sets null for NameModel.
I don't want to use EditorFor as i have to supply html and custom attributes to helpers.The binding for the partial view fails.it gives me object reference error in Registration view. How can i use such strongly typed Partial views with such a such Model class hierarchy as explained above ?
The simplest way to do this is to use a child action
#model MyNamespace.Models.Register.SuperModel
#{
Layout = "~/Views/_Layout.cshtml";
}
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "myForm" }))
{
<div id="form">
#Html.Action("MyNamePartialView")
</div>
#Html.TextBoxFor(m=>m.Register.UserName,new { #id="userName"})
#Html.TextBoxFor(m=>m.Register.Password,new { #id="password"})
<input type="submit" value="Register" id="btnRegister" />
}
make your action post accept 2 classes
public ActionResult Register(RegisterModel RegisterInfo, NameModel NameInfo)

Categories

Resources