System.InvalidOperationException: When submitting a message - c#

I am receiving the error message above. I have looked at other's issues and can't seem to pinpoint the error. Here is the code that I have for the controller. Here is the error that I am getting :
System.InvalidOperationException: The ViewData item that has the key 'RecieverID' is of type 'System.String' but must be of type 'IEnumerable<SelectListItem>'
public ActionResult Create()
{
ViewBag.RecieverID = new SelectList(db.AspNetUsers, "Id", "Email");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "RecieverID,TEXT")] Message message)
{
if (ModelState.IsValid)
{
var mes = new Message
{
SenderID = User.Identity.GetUserId(),
DATETIMEMADE = DateTime.Now,
TEXT = message.TEXT
};
db.Messages.Add(mes);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ReceiverID = new SelectList(db.AspNetUsers, "Id", "Email", message.RecieverID);
return View(message);
}
After that here is my view for creating a message:
#model MUE.Models.Message
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Message</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.RecieverID, "RecieverID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("RecieverID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.RecieverID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TEXT, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TEXT, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.TEXT, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Not sure where the issue is coming from but any help would be greatly appreciated.

First off, and not to be a grammar Nazi, but it should be "Receiver" not "Reciever".
Second, model.RecieverID indicates a single field, not a collection.
"new SelectList(..." is collection.
Please refer to this:
MVC - Set selected value of SelectList

You could create a ViewModel for the page such as:
public class MyViewModel
{
public SelectList ReceiverList
public MUE.Models.Message ReceivedMessage
}
Assign your values in the controller and then do something like:
#Html.DropDownListFor(model => model.ReceivedMessage.ReceiverID, Model.ReceiverList, new { #class = "form-control" })

Related

Submit form not hitting action, instead opening new page

FYI, I am also populating a field model.VdiId from a partial page using jQuery. When I am clicking the submit button of the form page, It is redirecting me to a blank page, instead of hitting the BookVdi action of Booking controller. I am throwing exception and putting breakpoints which are not hitting as well.
Below is the View Code:
#model HVDI.Models.BookingViewModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (#Html.BeginForm("BookVdi", "Booking", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<h4>Booking</h4>
<hr />
<div class="form-inline">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.VdiId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.VdiId, new { htmlAttributes = new { #class = "form-control disabled" } })
#Html.ValidationMessageFor(model => model.VdiId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.BookingDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BookingDate, new { htmlAttributes = new { #class = "form-control datepicker" } })
#Html.ValidationMessageFor(model => model.BookingDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TimeStart, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TimeStart, new { htmlAttributes = new { #class = "form-control timepicker" } })
#Html.ValidationMessageFor(model => model.TimeStart, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TimeEnd, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TimeEnd, new { htmlAttributes = new { #class = "form-control timepicker" } })
#Html.ValidationMessageFor(model => model.TimeEnd, "", new { #class = "text-danger" })
</div>
</div>
<div class="showing">
<input type="button" class="align-content-end" onclick="" id="btnSearch" value="Search" />
</div>
</div>
<br />
<div class="form-group">
<div class="table-dark" id="vdiSection">
</div>
</div>
<br />
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Book" class="btn btn-default" />
</div>
</div>
}
Below is the Controller code:
public ActionResult Index()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public void BookVdi(BookingViewModel bookingDetails)
{
if (!ModelState.IsValid)
{
throw new Exception();
}
Booking newBooking = new Booking();
newBooking.BookingDate = bookingDetails.BookingDate; //I am putting a breakpoint here
}
It is opening a blank page:
http://localhost:61110/Booking/BookVdi
You see empty page because you might not return anything when action executed properly. Please change your code as per below.
[HttpPost]
[ValidateAntiForgeryToken]
public void BookVdi(BookingViewModel bookingDetails)
{
if (!ModelState.IsValid)
{
ViewBag,Error = "Please, correct all errors.";
return View("YOURVIEWNAMEFOR FORM");
}
Booking newBooking = new Booking();
newBooking.BookingDate = bookingDetails.BookingDate;
// Write save code here
return RedirectToAction("Index"); // you must redirect to something when action executed.
}
Also add this ViewBag to see errors on view
#Html.AntiForgeryToken()
#Html.ValidationSummary()
#ViewBag.Error // add this line
<h4>Booking</h4>
Also look at this question if you need specific model errors to be shown in view question

Returning List<ModelObject> to Controller MVC [duplicate]

I cannot figure out why my view only passes back a NULL for a model to my controller.
This is for an Edit Post method. I checked other controllers with Edit Post methods that are structured the same way as this one and they work fine. It seems to be just this view and controller.
Here is my view:
#model Non_P21_Quote_System_v1._0.Models.gl_code
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
#if (TempData["Message"] != null)
{
<div style="color:green">
#TempData["Message"]
</div><br />
}
#if (ViewBag.error != null)
{
<div style="color:red">
<h3>#ViewBag.error</h3>
</div><br />
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>gl_code</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.GL_code, "GL Code", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.GL_code, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.GL_code, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.GL_description, "Gl Description", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.GL_description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.GL_description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.expense_type_ID, "Expense", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("expense_type_ID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.expense_type_ID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.eag, "Employee Account Group", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("eag", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.eag, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "gl_Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Here is my controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "ID,GL_code,GL_description,expense_type_ID,eag")] gl_code gl_code)
{
if (ModelState.IsValid)
{
db.Entry(gl_code).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("gl_Index");
}
ViewBag.eag = new SelectList(db.employee_account_group, "ID", "eag_name");
ViewBag.expense_type_ID = new SelectList(db.expense_type, "ID", "type", gl_code.expense_type_ID);
return View(gl_code);
}
When I debug it, I see the model being passed in is of value NULL. I am seeing this on the controller side at the the parameters part of the Edit method.
Its null because your model contains a property named gl_code and you have also named the parameter for your model gl_code in the POST method.
Change the name of one or the other and the model will bind correctly.
What is happening internally is that the form submits a name/value pair for each successful form control, in your case gl_code=someValue. The DefaultModelBinder first initializes a new instance of your model. It then reads the form values and finds a match for the property in your model and sets it to someValue. But it also finds a match in the method parameters and tries set the value of the parameter to someValue, which fails (because you cannot do gl_code gl_code = "someValue";) and the model becomes null.
It appears you have a property on your view model called gl_code. In your controller, you also refer to the view model as gl_code.
Try changing this.
public async Task<ActionResult> Edit(gl_code gl_code)
To
public async Task<ActionResult> Edit(gl_code model)

Form not submitting data between html and c# [duplicate]

I cannot figure out why my view only passes back a NULL for a model to my controller.
This is for an Edit Post method. I checked other controllers with Edit Post methods that are structured the same way as this one and they work fine. It seems to be just this view and controller.
Here is my view:
#model Non_P21_Quote_System_v1._0.Models.gl_code
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
#if (TempData["Message"] != null)
{
<div style="color:green">
#TempData["Message"]
</div><br />
}
#if (ViewBag.error != null)
{
<div style="color:red">
<h3>#ViewBag.error</h3>
</div><br />
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>gl_code</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.GL_code, "GL Code", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.GL_code, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.GL_code, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.GL_description, "Gl Description", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.GL_description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.GL_description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.expense_type_ID, "Expense", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("expense_type_ID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.expense_type_ID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.eag, "Employee Account Group", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("eag", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.eag, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "gl_Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Here is my controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "ID,GL_code,GL_description,expense_type_ID,eag")] gl_code gl_code)
{
if (ModelState.IsValid)
{
db.Entry(gl_code).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("gl_Index");
}
ViewBag.eag = new SelectList(db.employee_account_group, "ID", "eag_name");
ViewBag.expense_type_ID = new SelectList(db.expense_type, "ID", "type", gl_code.expense_type_ID);
return View(gl_code);
}
When I debug it, I see the model being passed in is of value NULL. I am seeing this on the controller side at the the parameters part of the Edit method.
Its null because your model contains a property named gl_code and you have also named the parameter for your model gl_code in the POST method.
Change the name of one or the other and the model will bind correctly.
What is happening internally is that the form submits a name/value pair for each successful form control, in your case gl_code=someValue. The DefaultModelBinder first initializes a new instance of your model. It then reads the form values and finds a match for the property in your model and sets it to someValue. But it also finds a match in the method parameters and tries set the value of the parameter to someValue, which fails (because you cannot do gl_code gl_code = "someValue";) and the model becomes null.
It appears you have a property on your view model called gl_code. In your controller, you also refer to the view model as gl_code.
Try changing this.
public async Task<ActionResult> Edit(gl_code gl_code)
To
public async Task<ActionResult> Edit(gl_code model)

Model returns null after post [duplicate]

I cannot figure out why my view only passes back a NULL for a model to my controller.
This is for an Edit Post method. I checked other controllers with Edit Post methods that are structured the same way as this one and they work fine. It seems to be just this view and controller.
Here is my view:
#model Non_P21_Quote_System_v1._0.Models.gl_code
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
#if (TempData["Message"] != null)
{
<div style="color:green">
#TempData["Message"]
</div><br />
}
#if (ViewBag.error != null)
{
<div style="color:red">
<h3>#ViewBag.error</h3>
</div><br />
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>gl_code</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.GL_code, "GL Code", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.GL_code, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.GL_code, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.GL_description, "Gl Description", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.GL_description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.GL_description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.expense_type_ID, "Expense", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("expense_type_ID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.expense_type_ID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.eag, "Employee Account Group", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("eag", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.eag, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "gl_Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Here is my controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "ID,GL_code,GL_description,expense_type_ID,eag")] gl_code gl_code)
{
if (ModelState.IsValid)
{
db.Entry(gl_code).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("gl_Index");
}
ViewBag.eag = new SelectList(db.employee_account_group, "ID", "eag_name");
ViewBag.expense_type_ID = new SelectList(db.expense_type, "ID", "type", gl_code.expense_type_ID);
return View(gl_code);
}
When I debug it, I see the model being passed in is of value NULL. I am seeing this on the controller side at the the parameters part of the Edit method.
Its null because your model contains a property named gl_code and you have also named the parameter for your model gl_code in the POST method.
Change the name of one or the other and the model will bind correctly.
What is happening internally is that the form submits a name/value pair for each successful form control, in your case gl_code=someValue. The DefaultModelBinder first initializes a new instance of your model. It then reads the form values and finds a match for the property in your model and sets it to someValue. But it also finds a match in the method parameters and tries set the value of the parameter to someValue, which fails (because you cannot do gl_code gl_code = "someValue";) and the model becomes null.
It appears you have a property on your view model called gl_code. In your controller, you also refer to the view model as gl_code.
Try changing this.
public async Task<ActionResult> Edit(gl_code gl_code)
To
public async Task<ActionResult> Edit(gl_code model)

Send a list of objects to controller without JSON

I'm doing a form that contains a List<object>. This List<object> must be sent to the controller but I don't want to use JSON. Is it possible? Do I have to test with id="MyField[i]" or anything like that?
Here is the Razor code that is targeted:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Ajout de Critères sur l'audit #Model.idAudit</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#foreach (var item in Model.criteresList)
{
<div class="form-group">
#Html.LabelFor(model => item.nomCritere, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => item.nomCritere, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => item.nomCritere, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => item.libelle, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => item.libelle, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => item.libelle, "", new { #class = "text-danger" })
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
And the Controller
[HttpPost]
public ActionResult Criteres(CritereViewModel model)
{
// Call BL to save them all
return RedirectToAction("Index");
}
Well this article explains everyting about binding arrays in MVC
If you want to post your form values with bare hands you need to do something like this:
#for (var i = 0 ;i < in Model.criteresList.Count();i++)
{
#Html.EditorFor(model => Model.criteresList[i].nomCritere, new { htmlAttributes = new { #class = "form-control" } })
}
the previous answer is viable and what you say also works (id = "MyField [i]") you just have to add the object properties.
#Html.Hidden(string.Format("model.criteresList[{0}].nomCritere", index),someValue)
<select name="model.criteresList[#index].nomCritere" value="someValue">
in controller
[HttpPost]
public ActionResult Criteres(CritereViewModel model)
{}

Categories

Resources