mvc 4 Model is null - c#

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; }
}

Related

Insert succeeds but the inserted value shows NULL in the back end ms sql database

I have a simple mvc5 code first application, It has a ms SQL database in the back-end and and a form in the front-end.
While I insert into database via the front end form, it does not generate any error, everything seems OK but when i check the back end database table, then all values in the newly inserted row are showing as NULL.
This is my code for model:
public class students
{
public int Id { get; set; }
[Display(Name = "Name")]
public string st_name { get; set; }
[Display(Name = "Father's Name")]
public string st_father_name { get; set; }
public string st_contact { get; set; }
}
This is the View Model class:
public class AddStudentViewModel
{
public students stdntss { get; set; }
}
This is the controller:
public ActionResult Index()
{
var std = _context.stdnts;
if (std==null)
{
return Content("Nothing Found");
}
return View(std);
}
public ActionResult AddStudent()
{
return View();
}
[HttpPost]
public ActionResult Insert(students st)
{
_context.stdnts.Add(st);
_context.SaveChanges();
return RedirectToAction("Index","Students");
}
And finally this is the view:
#model school2.ViewModels.AddStudentViewModel
#{
ViewBag.Title = "AddStudent";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>New student's registration form</h2>
#using (Html.BeginForm("Insert","Students"))
{
<div class="form-group">
#Html.LabelFor(m=> m.stdntss.st_name)
#Html.TextBoxFor(m=> m.stdntss.st_name, new { #class="form-control"})
</div>
<div class="form-group">
#Html.LabelFor(m => m.stdntss.st_father_name)
#Html.TextBoxFor(m => m.stdntss.st_father_name, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.stdntss.st_contact)
#Html.TextBoxFor(m => m.stdntss.st_contact, new { #class = "form-control" })
</div>
<button type="submit" class="btn btn-primary">Save</button>
}
Kindly assist me if anyone has any clue?
One way to solve this is to change the POST method to accept the same model as the view.
try changing
public ActionResult Insert(students st)
{
_context.stdnts.Add(st);
_context.SaveChanges();
return RedirectToAction("Index","Students");
}
to
public ActionResult Insert(AddStudentViewModel st)
{
_context.stdnts.Add(st.stdntss );
_context.SaveChanges();
return RedirectToAction("Index","Students");
}
or changing the model of the form to simply be student.
I think that change #Html.TextBoxFor(model=> model.stdntss.st_name, new { #class="form-control"}). because call Model, #model school2.ViewModels.AddStudentViewModel . Variable default Model.

Currency conversion api web service

I am a new to MVC and still learning! I am trying to create a very basic App in my web which allows users to convert money value according to their preference. I made the web APi and was successful to call the service to my forms. However, in my controller I managed to get the currencies (names) to the index view, but cannot post the form back once entering a value in the text box to generate the partial view! What am I doing wrong in my codes?!
Currency Controller
namespace MVC_ATM.Controllers
{
public class CurrencyController : Controller
{
[HttpGet]
// GET: Currency
public ActionResult Index()
{
CurrenciesClient Cur = new CurrenciesClient();
var listCurrency = Cur.findAll();
SelectList list = new SelectList(listCurrency,"Id", "CurrencyName");
ViewBag.listCurrencies = list;
return View();
}
[HttpPost]
public ActionResult Index(Currencies cur)
{
if (!ModelState.IsValid)
{
string errors = string.Join("<br />", ModelState.Values
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
return new ContentResult { Content = errors };
var rate = Convert.ToDecimal(cur.ConversionRate);
if (cur.CurrencyName == cur.CurrencyName)
{
ModelState.AddModelError("CurrencyCountry", "Can't make the conversion for the same value");
}
else if (cur.CurrencyName != cur.CurrencyName)
{
foreach (var currency in cur.CurrencyName)
{
ViewBag.Theresult = rate * cur.Value;
}
return PartialView("_CurrencyValue");
}
}
return View();
}
}
}
Currencies Model
namespace Project.Model
{
public class Currencies
{
public int Id { get; set; }
public string CurrencyName { get; set; }
public string CurrencyCountry {get; set;}
public decimal Value { get; set; }
public string ConversionRate { get; set; }
}
}
Index View
#model Project.Model.Currencies
#{
ViewBag.Title = "Index";
}
<h2>Currency</h2>
<body>
<div class="converter">
Convert: #Html.TextBoxFor(m => m.ConversionRate, new { #size = "5" })
<div class="form-group">
#Html.Label("Convert from", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownList("Currency List", ViewBag.listCurrencies as SelectList, "Please Select a currency")
</div>
</div>
<div class="form-group">
#Html.Label("Convert to", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownList("Currency List", ViewBag.listCurrencies as SelectList, "Please Select a currency")
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Convert</button>
</div>
</div>
</body>
Couple of things to notice, is the POST action and missing form tag in the view . You created a POST action that accepts Currencies model but the form doesn't post that. Only ConversionRate will bind to the model. To get the "Currency From" and "Currency To" and the "Conversion Rate" you will require a different approach/small changes.
ConversionModel.cs a new Model for index page that will capture your required fields.
public class ConversionModel
{
[Required]//decimal would be better but up to you requirement
public decimal ConversionRate { get; set; }
[Required]
public int FromCurrencyId {get;set;}
public SelectList FromCurrencies {get;set;}
[Required]
public int ToCurrencyId {get;set;}
public SelectList ToCurrencies {get;set;}
}
Get: while there is nothing wrong with what you've done, lets use a model approach and tightly bind it.
public ActionResult Index()
{
CurrenciesClient Cur = new CurrenciesClient();
var listCurrency = Cur.findAll();
ConversionModel model = new ConversionModel();
model.FromCurrencies = new SelectList(listCurrency,"Id", "CurrencyName");
model.ToCurrencies = new SelectList(listCurrency,"Id", "CurrencyName");
return View(model);
}
Post: Important thing here to notice is the SelectList will not be posted back. Only the ConversionRate, FromCurrencyId and ToCurrencyId are sent back not the Lists. If error occurs you will need to rebuild the lists and send it back in the model.
[HttpPost]
public ActionResult Index(ConversionModel curModel)
{
if(ModelState.IsValid)
{
if(curModel.FromCurrencyId ==curModel.ToCurrencyId)
{
//do something if same currecnies and return.
}
else
{
//Get the currencyList with rates from db
//use currency ToCurrencyId and FromCurrencyId to fetch the 2 currencies
// perform conversion with curModel.ConversionRate with existing logic
}
}
//Don'f forget to rebuild the Select Lists...
return View(curModel);
}
View:
#model Project.Model.ConversionModel
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("Index", "Currency", FormMethod.Post)
{
#Html.TextBoxFor(m => m.ConversionRate, new { #size = "5" })
#* Please check the syntax *#
#Html.DropDownListFor(m => m.FromCurrencyId , Model.FromCurrencies as SelectList)
#Html.DropDownListFor(m => m.ToCurrencyId , Model.ToCurrencies as SelectList)
<button type="submit" class="btn btn-primary">Convert</button>
}
Not a CUT_COPY_PASTE. please do check for errors if any. It is only an approach.
ajax POST probably the next thing to learn... Let us know.
You need to put your items inside a form like this:
#using (Html.BeginForm("Index", "Currency", FormMethod.Post)
{
// Your form items
}

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.

I cannot receive post data from a form in Controller

When posting the html form I can see null in the controller, so I am not able to add a Product to the database. What is wrong here?
public partial class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
}
public ActionResult CreateProduct()
{
return View();
}
[HttpPost]
public ActionResult CreateProduct(Product product) // this is always null
{
service.CreateProduct(product);
return RedirectToAction("Index");
}
#model WebApplication1.Models.Product
#{
ViewBag.Title = "CreateProduct";
}
<h2>CreateProduct</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
<input type="submit" value="Create" />
</fieldset>
}
in your get pass the model with empty values
public ActionResult CreateProduct()
{
Product prd= new Product();
return View(prd);
}
and check if this solves your problem

MVC3,PartialViews,Ajax Passing values

This is the model example.cs
namespace View_Partial_Editor.Models
{
public class ExampleView
{
...
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
public string Field4 { get; set; }
public string Field5 { get; set; }
...
}
}
I have this view example.cshtml:
#model View_Partial_Editor.Models.ExampleView
#{Html.RenderPartial("EditExample",Model);}
#Html.TextBoxFor(m => m.Field1)
Then i have this partialView EditExample.cshtml:
#model View_Partial_Editor.Models.ExampleView
#Html.HiddenFor(m => m.Field1)
#using (Ajax.BeginForm("EditExample", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "partial" }))
{
<div>
#Html.EditorFor(m => m, "Editor", null)
</div>
<p>
<input id="buttona" type="submit" value="Save" />
</p>
}
I have this controller ExampleController:
namespace View_Partial_Editor.Controllers
{
public class ExampleController : Controller
{
//
// GET: /Example/
public ActionResult Example()
{
return View();
}
[HttpPost]
public ActionResult EditExample(ExampleView example)
{
example.Field1 ="7";
return View("Example", example);
}
}
}
And this is the editor that is called in the partial editor.cshtml
#model View_Partial_Editor.Models.ExampleView
<div class="editor-label">
#Html.LabelFor(m => m.Field1 )
</div>
<div class="editor-field">
#Html.EditorFor(m => m.Field1)
#Html.ValidationMessageFor(m => m.Field1)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Field2)
</div>
<div class="editor-field">
#Html.EditorFor(m => m.Field2)
#Html.ValidationMessageFor(m => m.Field2)
</div>
My problem is that i want to modify the data of the model in the controller in the ajax call, and return the model modified to the exampleView.But when the ajax called finish the value that i change in the controller is not changed in the model
Edit: The thing that i want is to send the call to the ajax methos, save something in the database, then modify the model, and in the example view i want to have that model with the changes.
In this moment, if i replace the partial view with the result of the ajax, the model in the example view is not modified.Another way is to replace the full example view, so the model is received there, but i have to pass a lot of fields using Html.HiddenFor, is possible to make this without replacing the views only returnng the model with the changes
Try calling ModelState.Clear() in your HttpPost action method. Html helpers use the values in the ModelState first, then the Model. If you change a value in the model on a post therefore, you need to clear the value from the ModelState.

Categories

Resources