complex model stays null after post - c#

My question is related to this question and answer
The following complex model:
public class EditSubmissionModel
{
public string foo { get; set; }
public Submission submission { get; set; }
}
The simple model
[Table(Name = "Submission")]
public class Submission
{
[Column(IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
public int SubmissionId { get; set; }
[Column]
public string Title { get; set; }
}
The view:
#model Project.WebUI.Models.EditSubmissionModel
#{
ViewBag.Title = "editSubmission";
}
<h2>editSubmission</h2>
#using (Html.BeginForm())
{
<legend>SubmissionModel</legend>
#Html.EditorFor(m => m.foo)
#Html.EditorFor(m => m.submission)
<input type="submit" value="Save" />
}
the editorTemplate
#model Project.Domain.Entities.Submission
#Html.EditorFor(m => m.Title)
the controller
[Authorize]
[HttpPost]
public ActionResult editSubmission(string shortName, EditSubmissionModel model)
{
shortname = "second" (is ok)
model.foo = aaa (also ok i edited it on the view)
model.submission = null (not binded? or i dont know?)
I can't see the error, any ideas?

Status no repro. Steps:
Create a new ASP.NET MVC 3 application using the default template
Define 2 models:
public class Submission
{
public int SubmissionId { get; set; }
public string Title { get; set; }
}
public class EditSubmissionModel
{
public string foo { get; set; }
public Submission submission { get; set; }
}
Modify HomeController so that it looks like this:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string shortName, EditSubmissionModel model)
{
return Content(model.submission.Title);
}
}
Update ~/Views/Home/Index.cshtml view so that it looks like this:
#model EditSubmissionModel
#using (Html.BeginForm())
{
<legend>SubmissionModel</legend>
#Html.EditorFor(m => m.foo)
#Html.EditorFor(m => m.submission)
<input type="submit" value="Save" />
}
Add a custom editor template for the Submission type (~/Views/Home/EditorTemplates/.cshtml) like this:
#model Submission
#Html.EditorFor(m => m.Title)
Hit Ctrl+F5, fill in the form and submit. As totally expected the value you have entered in the Title textbox will be correctly bound and shown on the screen.
So I repeat the question that I've already asked you in the comments section: what did you do differently? You answered that it is a copy-paste from your code, but as I have illustrated you (with a full step-by-step guide) this is not the case.
Now here's a suspicion that I have. Your actual POST action looks like this:
public ActionResult editSubmission(string shortName, EditSubmissionModel submission)
and not like this:
public ActionResult editSubmission(string shortName, EditSubmissionModel model)
Notice the parameter name.

#Darin Dimitrov you were completely right, what do i do different. The code above was completely fine. The problem was the get command which looked like:
[Authorize]
public ActionResult editSubmission(string confShortName, string submission)
{
//do stuff
return View();
}
And the Modelbinder will get problems if the httpPost anywhere has same name like the HttpGet in my case string submission and Editsubmission.submission. Big thanks to your detailed step by step advice!

Related

How MVC creates c# class from html form?

we have some c# model
public class PartnerRegistrationForm
{
public string Name { get; set; }
public string Company { get; set; }
public string Email { get; set; }
}
class that contains this model
public class PartnerRegistrationFormHolder
{
public PartnerRegistrationForm PartnerRegistrationForm { get; set; }
}
view
#model WebApplication1.Models.PartnerRegistrationFormHolder
#using (Html.BeginForm("Index", "Registration", FormMethod.Post))
{
#Html.TextBoxFor(e => e.PartnerRegistrationForm.Name)
#Html.TextBoxFor(e => e.PartnerRegistrationForm.Email)
#Html.TextBoxFor(e => e.PartnerRegistrationForm.Company)
<button type="submit">Send</button>
}
this method TextBoxFor create inputs with long names like 'PartnerRegistrationForm.Company'
ok, its reflection magic
then i fill this form and submit it
i have view
[HttpPost]
public ActionResult Index(PartnerRegistrationFormHolder partnerRegistrationFormHolder)
{
return new HttpNotFoundResult();
}
i run my program with debug and take a breakpoint on this action
HOW MVC create object from form? can anyone explain me or give me some link where to read?
more reflection magic :) it's called model binding:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-2.1

C# MVC Post form not passing ID from view to controller

I am new to MVC. I work on an auction application. On the auction site, there should be a form for making a bid. I have a problem passing the auction parameter to the controller
My models:
public class Auctions
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string title { get; set; }
(..) some other fields
public List<Bid> bids = new List<Bid>();
}
public class BiddingViewModel
{
public Auctions auctionToSend { get; set; }
public double bid { get; set; }
}
My view:
#model BiddingViewModel
#using(Html.BeginForm("CreateBid", "Auction", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.HiddenFor(model=>model.auctionToSend)
#Html.EditorFor(model => model.bid)
<input type="submit" value="Make it work" />
}
and my controller:
[AllowAnonymous]
public ActionResult AuctionPage(int id)
{
var tmp = _context.Auctions.FirstOrDefault(i => i.ID == id);
BiddingViewModel bvm = new BiddingViewModel
{
auctionToSend = tmp,
bid = -1
};
return View(bvm);
}
[Authorize]
[HttpPost]
public async Task<ActionResult> CreateBid(BiddingViewModel bvm)
{
//After filling the form from view, the bvm.auctionToSend is null, whereas the bvm.bid value is visible
return RedirectToAction("AuctionList", "Auction");
}
My problem is that the auction data (perfectly visible in the view) is not sent back to the controller. I checked the internet and it showed me some naming-conflicts' solutions, so I made sure the naming is different, but this didn't fix my problem.
auctionToSend is a complex object and your use of #Html.HiddenFor(model=>model.auctionToSend) is generating
<input type="hidden" name="auctionToSend" value="yourAssembly.Auctions" ... />
If you just need the ID of the Auctions, then use
#Html.HiddenFor(m => m.auctionToSend.ID)
otherwise you need to generate a hidden input for each property of Auctions but that would be inefficient, particularly as Auctions contains a property which is a collection, so if you need the Auctions object in the POST method, better to just get it again based on the ID value your submitting.
As a side note, you really should be using a view model with just properties for the double Bid and int AuctionID

Form submission in partial views in MVC

I am developing a simple mvc application . The code is as follows:
Model .cs:
public class CustomModel
{
public IEnumerable<lang> lstlang { get; set; }
public IEnumerable<org> lstOrg { get; set; }
}
public class lang
{
public int langid { get; set; }
public string langName { get; set; }
}
public class org
{
public int orgId { get ;set;}
public string orgName { get; set; }
}
Controller.cs
public Action Index()
{
// Get data from database and fill the model
var model = new CustomModel();
return View(model);
}
public Action Partial()
{
// Get data from database and fill the model
var model = new CustomModel();
return PartialView(model);
}
[HttpPost]
public Action Partial(FormCollection frm, CustomModel model)
{
// Get data from database and fill the model
var model = new CustomModel();
return PartialView(model);
}
Index.cshtml
#model CustomModel
#Html.TextboxFor(x => x.lang.FirstOrDefault().id);
<input type="button" id="btn" />
#Html.RenderPartial("Partial", model)
Partial.cshtml
#model CustomModel
#Html.TextboxFor(x => x.lang.FirstOrDefault().id);
<input type="submit" id="submit" />
The thing is, when I click the submit button in the Partial.cshtml page, and examine the model in httppost method in public Action Partial(FormCollection frm, CustomModel model), the model contains null for both lists lstlang and lstOrg, but the formcollection[0] will give the selected textbox value.
What am I missing, or is this the right way of using partial views?
Don't use FirstOrDefault(). If you want to post something back to the front end with collections, you'll need to use indexing.
Public class CustomModel
{
public ICollection<lang> lstlang { get; set; }
public ICollection<org> lstOrg { get; set; }
}
#HTML.textboxfor(x=>x.lang[0].id);

Model properties are null when the form is submitted

On an ASP.NET MVC 5 project I have the following model:
public class ScheduleIndexModel {
public IPageList<DataModel> Data { get; set; }
public FormModel Form { get; set; }
public class DataModel {
public Int32 Id { get; set; }
public String[] Attendees { get; set; }
public String Location { get; set; }
public DateTime Date { get; set; }
} // DataModel
public class FormModel {
public String Location { get; set; }
public String Date { get; set; }
} // FormModel
}
The view is the following:
<form action="#Url.Action(MVC.Schedule.Index())" method="post">
#Html.LabelFor(x => x.Form.Date, "Date")
#Html.TextBoxFor(x => x.Form.Date)
#Html.LabelFor(x => x.Form.Location, "Location")
#Html.TextBoxFor(x => x.Form.Location)
#Html.SubmitButton("Filter", "Index", new { #class = "submit" })
#Html.AntiForgeryToken()
</form>
Then the HTTPPost controller action is as follows:
[HttpPost]
public virtual ActionResult Index(ScheduleIndexModel.FormModel model, Int32 p = 1) {
return View();
} // Index
When I submit the form the model is not null but its properties are even if I write something on the TextBoxes.
Does anyone knows what am I doing wrong?
You may need to use a binding prefix because your viewmodel is nested. Something like this may work:
public virtual ActionResult Index([Bind(Prefix = "Form")] FormModel model)
Your html helpers (e.g. #Html.TextBoxFor(x => x.Form.Date) will be generating html like this
<input name="Form.Date" .../>
but because your post method accepts parameter of type FormModel it cant match up (FormModel only has property Date, not property Form that has property Date).
You can either change you action method to
public virtual ActionResult Index(ScheduleIndexModel model,...
{
FormModel form = model.Form; // get the FormModel
or use the [Bind(Prefix..)] as suggested by Big Daddy

MVC4 validation summary not showing

Have created a model and with required fields and used to create a form like so:
Model:
public class formModel {
[Required]
public string name {get;set;}
[Required]
public string Add1 {get;set;}
etc....
}
View:
#model myProj.Models.formModel
#using (BeginForm("Action", "Controller", FormMethod.Post))
{
#Html.TextBoxFor(f => f.name)
#Html.TextBoxFor(f => f.Add1)
etc...
#Html.ValidationSummary()
<button type="submit" value="submit">Submit</button>
}
Controller:
[HttpPost]
public ActionResult Action(formModel f)
{
if (ModelState.IsValid)
{
// Do Stuff here
return RedirectToAction("Result");
}
return RedirectToAction("Form", new { id = "showForm" });
}
Problem is the validation summary is being displayed if the model is in valid. Have used same approach on lots of other forms and has been fine.
Any ideas?
When the model is invalid, do not use
return RedirectToAction("Form");
But
return View(f); // or return View("ViewName", f);

Categories