C# Databinding does not contain property with name - c#

I am creating a ListBoxFor with a MultiSelectList, but I get the following error: DataBinding: *.Models.Facilities does not contain a property with the name FacilitiesList.
Here's my view:
#model *.Models.Reservation
<div class="form-group">
#Html.LabelFor(model => model.FacilitiesList, "Facilities", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.ListBoxFor(model => model.FacilitiesList, ViewBag.FacilitiesList as MultiSelectList, htmlAttributes: new { #class = "form-control" })
</div>
</div>
The viewbag FacilitiesList is populated as follows:
public ActionResult Create()
{
ViewBag.FacilitiesList = new SelectList(_facilityrepository.GetAll(), "FacilitiesList", "FacilityType");
return View();
}

Solved it. Simple solution:
I changed this:
ViewBag.FacilitiesList = new SelectList(_facilityrepository.GetAll(), "FacilitiesList", "FacilityType");
to this:
ViewBag.FacilitiesList = new SelectList(_facilityrepository.GetAll(), "FacilityId", "FacilityType");

Related

MVC Client Side Validation Summary not showing when Model is Invalid

I'm using the MVC Validation nuget package called MVC Foolproof Validation.
I'm using it on my model to set a required to true if another model property was empty. The validation part works, as the ModelState is correctly set to invalid when the Id field and Location field are left empty. Inspecting the errors on the ModelState array I can see its working.
My problem is that the client side validation summary does not display. Here is how I've set things up. Can anyone spot my problem?
[DisplayName("Image Id")]
public string Id{ get; set; }
[DisplayName("Location Id")]
[RequiredIfEmpty("Id", ErrorMessage = "You must..etc"]
public string LocationId{ get; set; }
In my view I'm setting up the validation summary and inputs as follows
<div class="form-horizontal">
<hr/>
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
<div class="form-group">
#Html.LabelFor(model => model.SearchCriteria.Id, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.SearchCriteria.Id, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.SearchCriteria.Id, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SearchCriteria.LocationId, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.SearchCriteria.LocationId, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.SearchCriteria.LocationId,"", new {#class = "text-danger"})
</div>
</div>
In my controller action I'm checking the Model state. Do I need to call ModelState.AddModelError(..). I've tried that but perhaps there is a way I need to call it.
[HttpPost]
public ActionResult Search(SearchCriteria searchCriteria)
{
var searchViewModel = new SearchViewModel
{
SearchCriteria = searchCriteria
};
if (ModelState.IsValid)
{
...
}
//ModelState.AddModelError("LocationId", "test");
return View(searchViewModel);
}
Change the boolean parameter (excludePropertyErrors) in the ValidationSummary helper line to false:
#Html.ValidationSummary(false, "", new {#class = "text-danger"})
See https://msdn.microsoft.com/de-de/library/ee839464(v=vs.118).aspx
In my case I solved it changing from 'ModelOnly' to 'All':
From:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
To:
<div asp-validation-summary="All" class="text-danger"></div>
My problem was that my call to my action was being done through ajax. I really should have specified, people who helped here would have diagnosed the problem immediately. When the modelstate was invalid i was returning a new View(searchViewModel) but I had to update that to return the errors in json.
[HttpPost]
public ActionResult Search(SearchCriteria searchCriteria)
{
if (ModelState.IsValid)
{
var searchResults = _searchProvider.GetData(searchCriteria);
return Json(new
{
searchResults
}, JsonRequestBehavior.AllowGet);
}
string errorMessages = string.Join(" <br /> ", this.ModelState.Values
.SelectMany(v => v.Errors)
.Select(e => e.ErrorMessage));
return this.Json(new { HasError = true, ErrorMessages = errorMessages });
}

Html.DropDownListFor not working for specific list in specific view

I use this method in my controller to add some lists to ViewBag which is used by two actions: Create and Edit. The lists are properly set, some items have set Selected property true.
private void AddUsersAndTrucksListsToViewBag(string[] selectedUsers, int[] selectedTrucks)
{
ViewBag.UsersList = uow.UsersRepository
.GetAll(_siteId)
.Where(u => u.IsActive)
.Select(u => new SelectListItem()
{
Value = u.Id,
Text = $"{u.Name} {u.Surname}",
Selected = selectedUsers != null && selectedUsers.Contains(u.Id)
})
.ToArray();
ViewBag.TrucksList = uow.OspRepository
.GetAllTrucks(_siteId)
.Select(t => new SelectListItem()
{
Value = t.Id.ToString(),
Text = $"{t.Codename} {t.Manufacturer} {t.Model}",
Selected = selectedTrucks != null && selectedTrucks.Contains(t.Id)
})
.ToArray();
}
In Edit view:
<div class="form-group">
#Html.Label("Osoby", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedUserIds, (SelectListItem[])ViewBag.UsersList, new { #class = "form-control", multiple = "multiple" })
</div>
</div>
<div class="form-group">
#Html.Label("Samochody", htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedTruckIds, (SelectListItem[]) ViewBag.TrucksList, new {#class = "form-control", multiple = "multiple"})
</div>
</div>
And exactly the same in Create view:
<div class="form-group">
#Html.Label("Osoby", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedUserIds, (SelectListItem[])ViewBag.UsersList, new { #class = "form-control ", multiple = "multiple" })
</div>
</div>
<div class="form-group">
#Html.Label("Samochody", htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedTruckIds, (SelectListItem[]) ViewBag.TrucksList, new {#class = "form-control ", multiple = "multiple"})
</div>
</div>
The problem is that everything works fine in Edit view. But in Create view only second list has properly rendered selected HTML attributes. This can be seen on the screenshots
What's wrong with this? I found that it can be caused by having the same ViewBag property name as some of Model property name but it is not.
Both lists have multiple attribute.
This is HTML generated by ListBoxFor()
<select class="form-control " id="SelectedUserIds" multiple="multiple" name="SelectedUserIds">
<option value="525b1890-942f-4fb4-96de-56e04b6ca196">Jan Kowalski</option>
<option value="5b0e1c01-0e46-436c-aa9b-ac63e66d691f">Adam Pawlak</option>
</select>
<select class="form-control " id="SelectedTruckIds" multiple="multiple" name="SelectedTruckIds">
<option selected="selected" value="3">425[O]21 MAN 12.232</option>
</select>
New screenshots:

NullReferenceException in the cshtml page [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I am starting on ASP.net and I can not resolve the next problem.
System.NullReferenceException: La référence d'objet n'est pas définie à une instance d'un objet.
I forwards a User Id from User controller to this Action, who belongs to Email Controler. Then I want to give this Id to a new parameter.
public ActionResult Create(Guid? id)
{
ViewBag.Key_Destinataire = id;
return View();
}
Le code de ma page HTML :
#model ProjetWeb.Models.Email
////
#Html.LabelFor(model => model.Objet, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Objet, new { htmlAttributes = new { #class = "form-control" } })
///
<div class="form-group">
#Html.LabelFor(model => model.Key_Destinataire, "Key_Destinataire", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Model.Key_Destinataire.Value=ViewBag.Key_Destinataire;
#Html.ValidationMessageFor(model => model.Key_Destinataire, "", new { #class = "text-danger" })
</div>
</div>
English Translation;
Hello,
I start on ASP.net and I can not resolve the error below:
System.NullReferenceException : Object reference not set to an instance of an object.
my code below: I transmits the ID of a user of controller User controller in this action the Email. Then I want to assign the id to a new setting.
Your '#Model' is null. You didn't pass any model in controller to view.
Some reading: check this
You will need to pass the id from the controller action to the view in your return statement. For example:
public ActionResult Create(Guid? id)
{
return View(id);
}
This will now be available to you in your view if you declare #model Guid?. For example:
#model Guid?
<div class="form-group">
#Html.LabelFor(model => model, "Key_Destinataire", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Value)
#Html.ValidationMessageFor(model => model, "", new {#class = "text-danger"})
</div>
</div>

Viewmodel values not being returned to controller

I found some similar posts to mine, but I couldn't find an answer that suits my needs for this.
Problem is as follows:
I have a viewmodel like this:
public class PrefViewModel
{
public SelectList countries { get; set; }
public SelectList Provincies { get; set; }
public ApplicationUser user { get; set; }
public Preference MyPref{ get; set; }
public int mycountry { get; set; }
public int myprovince { get; set; }
}
my cshtml looks like this:
#using (Html.BeginForm("Index","Preferences", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
#Html.LabelFor(model => model.user.UserName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="control-label col-md-10">
<span class="textvak">
#Html.TextBoxFor(model => model.user.UserName, new { disabled = "disabled", #readonly = "readonly" })
</span>
#Html.ValidationMessageFor(model => model.user.UserName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.user.Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="control-label col-md-10">
<span class="textvak">
#Html.TextBoxFor(model => model.user.Email, new { disabled = "disabled", #readonly = "readonly" })
</span>
#Html.ValidationMessageFor(model => model.user.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.user.Unhashed, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.user.Unhashed, new { htmlAttributes = new { #class = "form-control", type = "password" } })
#Html.ValidationMessageFor(model => model.user.Unhashed, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.user.Provincie.Land, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="control-label col-md-10">
#Html.DropDownListFor(model => model.mycountry, Model.countries, new { Name = "ddlLand", id = "ddlLanden", #class = "textvak" })
#Html.ValidationMessageFor(model => model.user.Provincie.Land, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.user.Provincie, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="control-label col-md-10">
#Html.DropDownListFor(model => model.myprovince, Model.Provincies, new { #class = "textvak" })
#Html.ValidationMessageFor(model => model.user.Provincie, "", new { #class = "text-danger" })
</div>
</div>
<br />
<table>
<tr>
<td>
<input type="submit" value=#Resources.Wijzig class="btn btn-default" />
</td>
</tr>
</table>
}
and in my controller I try to get the posted PrefViewModel back as follows:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(PrefViewModel TestMymodel)
{
if (ModelState.IsValid)
{
int myCountry = TestMymodel.mycountry;
int myprovince = TestMymodel.myprovince;
}
return View();
}
My problem is that the PrefViewModel TestMymodel never is filled with the values I thought i'm posting back. Even more strange to me is the fact that I do get the Unhashed password back, but all other values are 0 or null.
I can put values inside the PrefViewModel to load the page and that works, but on Posting it's almost entirely empty.
Any ideas?
edit: Would it make any difference that I did change the default model to one that I made up myself? Cause when I Call the Create action for example, I do get the values back in my post (from create offcourse). I'm getting a bit desperate
edit2: this is what was posted:
__RequestVerificationToken:-JYcw0CH2zZ7WrGUiYJM6-R6VxfL41ykTD5EHUjgtyyFcN01AaUU61BYuaRNr4oPdEvDq09aYsOFdb8fObJTXMnTKulADVkGY8CrBG3U71QXw0g7Th86WKl1up4059Zy7mW0SlrWGJpehed586v_5g2
user.Unhashed:Jonas1234-
user.Unhashed:Jonas1234-
ddlLand:1
ddlProvincie:3
(can't add picture with my reputation, so here a link to the full post: http://postimg.org/image/id95wjcxp/ )
Ok, when I change the name of the dropdownlists to the PrefViewModel property name those values get returned correct.
It appears that you have overriden the names of the drop down lists to some values which are different than the property names in your view model. That's why the values are not successfully bound back. Make sure that your input fields respect the same names as the properties on your view model if you want the default model binder to be able to bind them back to the view model.
Also your username textbox has the disabled flag:
#Html.TextBoxFor(model => model.user.UserName, new { disabled = "disabled", #readonly = "readonly" })
so it will not be submitted back to the server. You might need to add an additional hidden field if you want those values to travel back. Or simply use readonly without disabled attribute. Both attributes prevent the user from modifying the value in the corresponding input field but in addition to that the disabled attribute strips it from the POST payload when the form is submitted.
So you may use:
#Html.TextBoxFor(model => model.user.UserName, new { #readonly = "readonly" })

UpdateModel not working (MVC)

I've been following the nerd dinner tutorial. I branched off to create my own project based on it and I'm having trouble getting UpdateModel to work. It seems pretty complicated so I'll try to explain it in as much detail below.
In ServersController.cs:
public ActionResult Create(FormCollection formValues)
{
Server server = new Server();
try
{
UpdateModel(server); <----- This is not working
// server.Name = "testAdd";
// server.OS = "2008 R2";
serverRepository.Add(server);
serverRepository.Save();
return RedirectToAction("Details", new { id = server.ServerID });
}
catch
{
**not important**
}
If I try to use UpdateModel(Server), nothing gets saved to the database table. However, If I comment out that line, and use the commented lines in the code that sets the server.Name and server.OS, this DOES save it to the table. However, any other form input that's being posted doesn't save..
For example, if I explicitly set the server.Name and server.OS as in the code above, but then set other properties such as LastBackedUp and Model through the form, none of the properties set from the form are saved to the database table, nor are they reflected in the "details" view when the page gets redirected.
Here's the code for the "Details" GET method, also in ServersController.cs:
public ActionResult Details(int id)
{
Server server = serverRepository.GetServer(id);
RackInfo rackInfo = rackRepository.GetRack(id);
if (server == null)
return View("NotFound");
else
return View(new ServerDetailViewModel(rackInfo, server));
}
Basically, After the new server is created and saved, it's supposed to load the above "Detail" view, which uses a "ServerDetailViewModel" class to generate some data to pass to the view.
Here's the ServerDetailViewModel() code:
public class ServerDetailViewModel
{
public RackInfo RackInfo { get; private set; }
public Server Server { get; private set; }
public string Name { get; private set; }
public ServerDetailViewModel(RackInfo rackInfo, Server server)
{
Server = server;
RackInfo = rackInfo;
*more code here that sets stuff*
}
}
I think my problem has something to do with how my form parameters are passed around.
It seems odd that I can explicitly code in some server properties, and then save those into the database table. But when I try to do anything with UpdateModel, nothing seems to go through. When I use UpdateModel, it will redirect me to the details page, but none of the values I input for the properties seem to appear. Additionally, none of the properties I put in through the form gets saved to the database table.
If any of you have walked through the Nerd Dinner tutorial (http://weblogs.asp.net/scottgu/archive/2009/04/28/free-asp-net-mvc-nerddinner-tutorial-now-in-html.aspx), that's what I've been using. When I got through about halfway, I decided to start a new project that implemented what I was using.
I was initially able to get Create to work, but after adding another separate repository to the controller, the create method broke..
Any input or insight on this would be much appreciated. Please let me know if you need any additional information.
Thanks S.O.!!
EDIT (Including the "Create" Form):
#model PACSSL.Models.ServerFormViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Server</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Server.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.Name)
#Html.ValidationMessageFor(model => model.Server.Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Domain, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.Domain, Model.Domain)
#Html.ValidationMessageFor(model => model.Domain)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.BackedUp, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.BackedUp, Model.BackedUp)
#Html.ValidationMessageFor(model => model.BackedUp)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.Role, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.Role)
#Html.ValidationMessageFor(model => model.Server.Role)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.GroupOwner, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.GroupOwner)
#Html.ValidationMessageFor(model => model.Server.GroupOwner)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.PatchNotes, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.PatchNotes)
#Html.ValidationMessageFor(model => model.Server.PatchNotes)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.LastPatched, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.LastPatched) Format: yyyy-mm-dd
#Html.ValidationMessageFor(model => model.Server.LastPatched)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PatchedBy, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.PatchedBy, Model.PatchedBy)
#Html.ValidationMessageFor(model => model.PatchedBy)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.VP, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.VP, Model.VP)
#Html.ValidationMessageFor(model => model.VP)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.VMHost, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.VMHost)
#Html.ValidationMessageFor(model => model.Server.VMHost)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.Location, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.Location)
#Html.ValidationMessageFor(model => model.Server.Location)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.PurchaseDate, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.PurchaseDate) Format: yyyy-mm-dd
#Html.ValidationMessageFor(model => model.Server.PurchaseDate)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.OS, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.OS)
#Html.ValidationMessageFor(model => model.Server.OS)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.Model, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.Model)
#Html.ValidationMessageFor(model => model.Server.Model)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.DellST, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.DellST)
#Html.ValidationMessageFor(model => model.Server.DellST)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.ServiceContract, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.ServiceContract) Format: yyyy-mm-dd
#Html.ValidationMessageFor(model => model.Server.ServiceContract)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.IsLive, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.IsLive)
#Html.ValidationMessageFor(model => model.Server.IsLive)
</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>
}
Here's your problem.
When you generate a form field with the expression model => model.Server.OS, you produce a field that has a 'name' attribute like this:
"Server.OS"
Then, when you try and bind it to a model, it will bind to a model property matching the expression "Server.OS" - so, if your model object is server, it will bind to the following:
server.Server.OS
When, I presume, you want to bind to server.OS. My suggestion would be to flatten out your view model so instead of having Model.Server.OS you just have Model.OS. Then when you do...
UpdateModel(server);
... it should bind the "OS" field to the "OS" property.
In short: your view model has an extra level of property nesting compared to your server object, so there is a mismatch in the generated field names and the properties you're trying to bind to.
Better still, bind back to the same view model by modifying your controller action to have the signature:
public ActionResult Create(ServerDetailViewModel model)
And then do the mapping manually in the controller (or some static mapping class) - your view models and domain model should be completely independent.
You are trying to update a "empty" Model. It is empty because you are creating a new instance.
Server server = new Server();
try
{
//At this point you have an empty model because you just
//created a new Instance of your Server class,
//It is updating the Model with all Null values because they aren't assigned to anything
UpdateModel(server); <----- This is not working
//Here you assign values to your model, hence why they are not null anymore
// Your other values aren't getting saved because they still don't have a value.
server.Name = "testAdd";
server.OS = "2008 R2";
serverRepository.Add(server);
serverRepository.Save();
return RedirectToAction("Details", new { id = server.ServerID });
}

Categories