Object error displaying a list from ViewBag - asp.net-mvc-3

In the controller I populate the ViewBag with Types (TypeID, Name)
ViewBag.Types = types.ToList();
then in the view
#foreach (var item in ViewBag.Types)
{
#item.Name
}
This errors with:
'object' does not contain a definition for 'Name'

ViewBag ,ViewData or such dynamic Magic items are evil because they will never tell you whether your view is failing due to a misspelling error, while using a strongly-typed model you will get a compile-time error when there is a problem. And also you get Intellisense support too.
Why not use strongly typed approach ?
public ActionResult Create()
{
return View(types.ToList());
}
And make your View strongly typed to the object/objects
#model IList<Types>
#foreach(var item in Model)
{
<p>#item.Name</p>
}

Lets suppose your types is a list of foo.
Pass your ViewBag.Types just the way you did and in the view do this :
#{
var TypeList= (List<foo>)ViewBag.Types;
}
and then just do:
#foreach (var item in TypeList)
{
#item.Name
}
Note:You might need to write the full path to your foo entity

Related

Error after submitting from a ajax form [duplicate]

This question and community wiki answer has been added to assist in closing out numerous unanswered questions as discussed in this meta post.
I have some code and when it executes, it throws an exception saying:
The model item passed into the dictionary is of type Bar but this dictionary requires a model item of type Foo
What does this mean, and how do I fix it?
The error means that you're navigating to a view whose model is declared as typeof Foo (by using #model Foo), but you actually passed it a model which is typeof Bar (note the term dictionary is used because a model is passed to the view via a ViewDataDictionary).
The error can be caused by
Passing the wrong model from a controller method to a view (or partial view)
Common examples include using a query that creates an anonymous object (or collection of anonymous objects) and passing it to the view
var model = db.Foos.Select(x => new
{
ID = x.ID,
Name = x.Name
};
return View(model); // passes an anonymous object to a view declared with #model Foo
or passing a collection of objects to a view that expect a single object
var model = db.Foos.Where(x => x.ID == id);
return View(model); // passes IEnumerable<Foo> to a view declared with #model Foo
The error can be easily identified at compile time by explicitly declaring the model type in the controller to match the model in the view rather than using var.
Passing the wrong model from a view to a partial view
Given the following model
public class Foo
{
public Bar MyBar { get; set; }
}
and a main view declared with #model Foo and a partial view declared with #model Bar, then
Foo model = db.Foos.Where(x => x.ID == id).Include(x => x.Bar).FirstOrDefault();
return View(model);
will return the correct model to the main view. However the exception will be thrown if the view includes
#Html.Partial("_Bar") // or #{ Html.RenderPartial("_Bar"); }
By default, the model passed to the partial view is the model declared in the main view and you need to use
#Html.Partial("_Bar", Model.MyBar) // or #{ Html.RenderPartial("_Bar", Model.MyBar); }
to pass the instance of Bar to the partial view. Note also that if the value of MyBar is null (has not been initialized), then by default Foo will be passed to the partial, in which case, it needs to be
#Html.Partial("_Bar", new Bar())
Declaring a model in a layout
If a layout file includes a model declaration, then all views that use that layout must declare the same model, or a model that derives from that model.
If you want to include the html for a separate model in a Layout, then in the Layout, use #Html.Action(...) to call a [ChildActionOnly] method initializes that model and returns a partial view for it.
This question already has a great answer, but I ran into the same error, in a different scenario: displaying a List in an EditorTemplate.
I have a model like this:
public class Foo
{
public string FooName { get; set; }
public List<Bar> Bars { get; set; }
}
public class Bar
{
public string BarName { get; set; }
}
And this is my main view:
#model Foo
#Html.TextBoxFor(m => m.Name, new { #class = "form-control" })
#Html.EditorFor(m => m.Bars)
And this is my Bar EditorTemplate (Bar.cshtml)
#model List<Bar>
<div class="some-style">
#foreach (var item in Model)
{
<label>#item.BarName</label>
}
</div>
And I got this error:
The model item passed into the dictionary is of type 'Bar', but this
dictionary requires a model item of type
'System.Collections.Generic.List`1[Bar]
The reason for this error is that EditorFor already iterates the List for you, so if you pass a collection to it, it would display the editor template once for each item in the collection.
This is how I fixed this problem:
Brought the styles outside of the editor template, and into the main view:
#model Foo
#Html.TextBoxFor(m => m.Name, new { #class = "form-control" })
<div class="some-style">
#Html.EditorFor(m => m.Bars)
</div>
And changed the EditorTemplate (Bar.cshtml) to this:
#model Bar
<label>#Model.BarName</label>
Observe if the view has the model required:
View
#model IEnumerable<WFAccess.Models.ViewModels.SiteViewModel>
<div class="row">
<table class="table table-striped table-hover table-width-custom">
<thead>
<tr>
....
Controller
[HttpGet]
public ActionResult ListItems()
{
SiteStore site = new SiteStore();
site.GetSites();
IEnumerable<SiteViewModel> sites =
site.SitesList.Select(s => new SiteViewModel
{
Id = s.Id,
Type = s.Type
});
return PartialView("_ListItems", sites);
}
In my case I Use a partial view but runs in normal views
Consider the partial map.cshtml at Partials/Map.cshtml. This can be called from the Page where the partial is to be rendered, simply by using the <partial> tag:
<partial name="Partials/Map" model="new Pages.Partials.MapModel()" />
This is one of the easiest methods I encountered (although I am using razor pages, I am sure same is for MVC too)
First you need to return an IEnumerable version of your model to the list view.
#model IEnumerable<IdentityManager.Models.MerchantDetail>
Second, you need to return a list from the database. I am doing it via SQL Server, so this is code I got working.
public IActionResult Merchant_Boarding_List()
List<MerchantDetail> merchList = new List<MerchantDetail>();
var model = new MerchantDetail();
try
{
using (var con = new SqlConnection(Common.DB_CONNECTION_STRING_BOARDING))
{
con.Open();
using (var command = new SqlCommand("select * from MerchantDetail md where md.UserGUID = '" + UserGUID + "'", con))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
model.biz_dbaBusinessName = reader["biz_dbaBusinessName"].ToString();
merchList.Add(model);
}
}
}
}
}
catch (Exception ex)
{
}
return View(merchList);
Passing the model value that is populated from a controller method to a view
public async Task<IActionResult> Index()
{
//Getting Data from Database
var model= await _context.GetData();
//Selecting Populated Data from the Model and passing to view
return View(model.Value);
}
one more thing.
if your view is a partial/sub page and the model for that partial view is null for some reason (e.g no data) you will get this error. Just need to handle the null partial view model

MVC3 System.Collections.Generic.List pass the wrong model item

Hello everyone I have checked my controller and view it seems there is no problem but I get System Colletion error.
Here is my controller
public ViewResult Index()
{
return View(db.banner.ToList());
}
Here is My View
{
#model IEnumerable<icerik.Models.banner>
}
And I get this error
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[icerik.Models.banner]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[icerik.Models.contents]'.
Maybe you have a partial in your main view:
#Html.Partial("SomePartial")
and this partial is strongly typed to IEnumerable<contents>:
#model IEnumerable<icerik.Models.contents>
So make sure that you are passing the correct model to this partial. If you do not specify anything to the Partial helper (as in my example) the main model will be passed to this partial.
So always specify the correct model:
#Html.Partial("SomePartial", SomeModelInstance)

Return a view from Post method

I have this post method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Invitations(SuperInvitationsEditModel model)
{
...
var newmodel = new SuperInvitationsEditModel();
if (hasErrors)
{
SuperInvitationsErrorModel newErrorModel = new SuperInvitationsErrorModel();
newErrorModel.Errors = model.Errors;
return View(newErrorModel);
}
return View(newmodel);
}
When this code in the if(hasErrors) executes I get this error.
The model item passed into the dictionary is of type 'MyProject.Models.SuperInvitationsErrorModel', but this dictionary requires a model item of type 'MyProject.Models.SuperInvitationsEditModel'.
I thought I can do this since the return value of the method is a generic ActionResult. Can anyone tell me why is this not working?
because your current view is strongly typed. change the code as
return View("yourviewname",newErrorModel);
It has nothing to do with casting ViewResult to ActionResult. The problem is, that you have strongly typed view that expects the model of type SuperInvitationsEditModel (see #model on the top of Invitations.cshtml), but you are passing the model of type SuperInvitationsErrorModel to it.
You should merge the two view model classes (SuperInvitationsEditModel and SuperInvitationsErrorModel) into one, or create a standalone view for each of them.

DropDownListFor & Navigation Properties

I'm running into an issue trying to use #Html.DropDownListFor().
I have a model with a navigation property on it:
public class Thing {
...
public virtual Vendor Vendor { get; set; }
}
In the controller I'm grabbing the vendor list to throw into the ViewBag:
public ActionResult Create() {
ViewBag.Vendors = Vendor.GetVendors(SessionHelper.CurrentUser.Unit_Id);
return View();
}
The html item in the view looks like this:
#Html.DropDownListFor(model => model.Vendor, new SelectList(ViewBag.Vendors, "Id", "Name"), "---- Select vendor ----")
#Html.ValidationMessageFor(model => model.Vendor)
The dropdown list is being rendered, and everything seems fine until I submit the form. The HttpPost Create method is returning false on the ModelState.IsValid and throwing a Model Error: The parameter conversion from type 'System.String' to type '...Models.Vendor' failed because no type converter can convert between these types.
If I let the page post through, I end up with a server error:
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: items
After searching high and low I haven't been able to find a reason that the #Html.DropDownListFor() isn't properly auto-binding a Vendor object to the navigation property.
Any help would be greatly appreciated.
EDIT:
I ended up having to explicitly set the ForeignKey attributes so that I could directly access "Vendor_Id" then I changed the DropDownListFor to point to "Vendor_Id" instead of the navigation property. That seems to work.
I have found that the best way to do this is as follows. Change the controller to create the SelectListItems.
public ActionResult Create() {
ViewBag.Vendors = Vendor.GetVendors(SessionHelper.CurrentUser.Unit_Id)
.Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.Name),
Value = option.Id.ToString()
});
return View();
}
Then modify the view as follows:
#Html.DropDownListFor(model => model.Vendor, (IEnumerable<SelectListItem>)ViewBag.Vendors, "---- Select vendor ----")
#Html.ValidationMessageFor(model => model.Vendor)
You have to cast the ViewBag.Vendors as (IEnumerable).
This keeps the views nice and neat. You could also move the code that gets the SelectListItems to your repo and put it in a method called something like GetVendorsList().
public IEnumerable<SelectListItem> GetVendorsList(int unitId){
return Vendor.GetVendors(unitId)
.Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.Name),
Value = option.Id.ToString()
});
}
This would separate concerns nicely and keep your controller tidy.
Good luck
I have replied similar question in following stackoverflow question. The answer is good for this question too.
Validation for Navigation Properties in MVC (4) and EF (4)
This approach doesn't publish the SelectList in controller. I don't think publishing SelectList in controller is good idea, because this means we are taking care of view part in controller, which is clearly not the separation of concerns.

Unable to list Users in a view using MVC3

I am trying to list all users in a view but with no success. There are loads of questions here referring to the same problem and I have tried most of the replies, but for some reason I cannot get it to work. The following is the simplest implementation I could come up with but the error message is the same whatever method I use.
Compiler Error Message: CS1061: 'object' does not contain a definition for 'UserName' and no extension method 'UserName' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
#{
ViewBag.Title = "Admin";
}
<ul>
#foreach (var user in Membership.GetAllUsers())
{
<li>Name: #user.UserName </li>
}
</ul>
Any suggestions or advice would be greatly appreciated. Many Thanks
Use MembershipUser instead of var.
#foreach (MembershipUser user in Membership.GetAllUsers())
{
<li>Name: #user.UserName</li>
}
This being said I hope you realize that this is a total anti-MVC pattern. It's not the views responsibility to pull/fetch data from some stores. They should only use data that it is being passed to them from a controller action under the form of a strongly typed view model.
So here's the correct way to do this.
As always you start by defining a view model which will contain the data that you need to show in your view (in this case a list of usernames):
public class UserViewModel
{
public string Name { get; set; }
}
then a controller action:
public ActionResult Index()
{
var model = Membership
.GetAllUsers()
.Cast<MembershipUser>()
.Select(x => new UserViewModel
{
Name = x.UserName
});
return View(model);
}
then a corresponding strongly typed view:
#model IEnumerable<UserViewModel>
<ul>
#Html.DisplayForModel()
</ul>
and a display template for a given user which will be rendered for each item of the model collection (~/Views/Shared/DisplayTemplates/UserViewModel.cshtml):
#model UserViewModel
<li>Name: #Model.Name</li>

Resources