Unable to list Users in a view using MVC3 - asp.net-mvc-3

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>

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

Object error displaying a list from ViewBag

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

How to Post Partial View Data?

Any input much appreciated :)
I want to know one thing whether I can post multiple partial views data in MVC?(means i want to update partial views data to DATABASE)
Here is the Example:
Model:-
public class PassengerViewModel
{
public List<PassengerModel> Passengers { get; set; }
public ContactModel Contact { get; set; }
}
Controller:-
[RequiredAuthentication]
public ActionResult Passenger()
{
var passengrViewMdl = new PassengerViewModel()
{
Contact = new ContactModel(),
Passengers = psngrService.LoadPassengers(Convert.ToInt32(Session["LPORefNO"]))
};
return View(passengrViewMdl);
}
[HttpPost]
public ActionResult Passenger(PassengerViewModel passengerViewModel)
{
Here i want to update Passengers & Contact information
}
View:-
#model QR.LPO.Core.Models.PassengerViewModel
#{
ViewBag.Title = "Add Passengers";
}
#using (Html.BeginForm())
{
#Html.Partial("_Passenger", Model.Passengers);
#Html.Partial("_PassengerContact", Model.Contact);
<input type="submit" value="Submit" />
}
Thanks.
Yes, indeed you can, but, controller usually works only with one model per request, so either your model should have declared within it properties of both partial submodels, or submodels themselves.
This is possible due to HTML specifications, all data on form, which has submit buttom is send to submit action url.
This will almost work as you have it - there's nothing inherent to partials that would prevent this, in the end the html that's output is all that's important.
The problem with your code is that presumably the model of your _Passenger view is of type Passengers and the model of your _PassangerContact view is of type Contact. What this means is that if you standard HtmlHelper extensions (like Html.Textbox(...) or Html.TextboxFor(...) the fields they generate will not have full names like Contact.Name, but instead just names relative to their model, like Name. This will cause modelbinding to fail in your post action.
You can solve this in a number of ways.
Simply use the same model type (PassengerViewModel) in your sub-views, and write code like #Html.TextboxFor(m => m.Contact.Name).
Instead of using Html.Partial, use Html.EditorFor(...). This passes the proper prefix information into the child view so the field names are generated properly.
Explicitly set the prefix yourself
Like this:
#{
var childViewData = new ViewDataDictionary(this.ViewData);
childView.TemplateInfo.HtmlFieldPrefix = "Contact";
}
#Html.Partial("_PassengerContact", Model.Contact, childViewData)
You could also look at creating a Html.PartialFor overload yourself, as described in this stackoverflow question: ASP.NET MVC partial views: input name prefixes

MVC OrderBy EditorFor IEnumerable

I have just registered, and this is my first post, so please bear with me if the question is not the best. I have had a look about and can't find an answer that suits my requirements; this is possibly because it's not possible to achieve what I want.
I have a partial view which pulls through an IEnumerable list of EditorFor fields from a viewmodel:
#model DocumentViewModelContainer
#Html.EditorFor(m => m.Document.Metadata)
The DocumentViewModelContainer has the following code:
public class DocumentViewModelContainer
{
public DocumentViewModel Document
{
get;
set;
}
The DocumentViewModel has the following code:
public class DocumentViewModel
{
public IEnumerable<DocumentMetadataFieldViewModel> Metadata
{
get;
set;
}
}
There's a ton of other objects in both view models that I've left out as being irrelevant in this question. The DocumentMetadataFieldViewModel is made up of several fields of standard types (int, strings etc.)
What I'm trying to achieve is adding an OrderBy to this list pulled back by ordering by an object in the bottom view model, such as follows:
#model DocumentViewModelContainer
#Html.EditorFor(m => m.Document.Metadata.OrderBy(i => i.InstanceFieldOrder))
However this gives the error:
System.InvalidOperationException : Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
I'm not only very new to MVC, but to C# in general; this project has had me learning the language on the fly, so please play nice :)
Thanks,
Mark
You should do this ordering in your controller action which is responsible to retrieve your view models and pass them to the view.
You could always perform the following horror in your view:
#model DocumentViewModelContainer
#{
Model.Document.Metadata = Document.Metadata.OrderBy(i => i.InstanceFieldOrder).ToList();
}
#Html.EditorFor(m => m.Document.Metadata)
but promise me you won't do that.

How to post the selected value of a selectlist to the controller using a view model?

This question has been asked in various forms but none of the answers seem to fit my situation. I am simply trying to retrieve the selected value of a dropdown list in my controller.
Here is my code:
ViewModel.cs
public class ViewModel
{
public ViewModel() {}
public ViewModel(Contact contact, IEnumerable<State> states)
{
this.Contact = contact;
this.States = new SelectList(states, "Id", "Name", contact.StateId);
}
public Contact Contact {get;set;}
public SelectList States {get;set;}
}
Controller.cs
[HttpPost]
public ActionResult Edit(ViewModel viewModel)
{
_contactService.UpdateContact(viewModel.Contact);
return RedirectToAction("Item", new {id = viewModel.Contact.Id});
}
View.cshtml
<button type="submit" onclick="javascript:document.update.submit()"><span>Update</span></button>//aesthic usage.
#{using (Html.BeginForm("Edit", "Controller", FormMethod.Post, new { name = "update" }))
{
#Html.HiddenFor(m => m.Contact.Id)
#Html.LabelFor(m => m.Contact.Name, "Name:")
#Html.TextBoxFor(m => m.Contact.Name)
<label for="state">State:</label>
#Html.DropDownList("state", Model.States)
}
}
Everything works as expected except that no values from the dropdownlist are passed in my posted viewModel to the controller. The edit page and all fields load correctly. The dropdowns bind correctly and have their selected values displayed properly. However, when I post I only get a "Contact" object passed to the controller. The "States" SelectList object is null.
I tried mapping a "StateId" property in my viewModel contstructor but that did not work either. What am I doing wrong?
Thanks.
I hate answering my own questions but based on the multiple issues I had coupled with the myriad of answers available I thought I would summarize my findings.
First off thanks for Filip, his answer did not exactly fix my problem but it led me in the right direction. +1
If you are creating a form for viewing and editing that requires a drop down list, here are some suggestions and gotchas. I will start with a list of parameters that I needed to fit my needs.
Strongly typed views in my view are preferable. Minimize magic strings.
View models should contain as little logic and extraneous elements as possible. There only job should be to facilitate a collection of data objects.
The drop down list should display the selected value.
The selected value should map easily back to the view model on form submit.
This may sound like an obvious and easily obtainable list but for someone new to MVC, it is not. I will revise my code from above with comments. Here is what I did.
ViewModel.cs
public class ViewModel
{
public ViewModel() {}
public ViewModel(Contact contact, IList<State> states)
{
//no need to pass in a SelectList or IEnumerable, just what your service or repository spits out
this.Contact = contact;
this.States = states;
}
public Contact Contact {get;set;}
public IList<State> States {get;set;}
}
Controller.cs //nothing really different than above
public ActionResult Edit(int id)
{
var contact = _contactService.GetContactById(id);
var states = _stateService.GetAllStates();
return View(new ViewModel(contact, states));
}
public ActionResult Edit(ViewModel viewModel)
{
_contactService.UpdateContact(viewModel.Contact);
return RedirectToAction("Edit", new {id = viewModel.Contact.Id });
}
View//thanks goes to Artirto at this post
#{using (Html.BeginForm("Edit", "Controller", FormMethod.Post))
{
#Html.HiddenFor(m => m.Contact.Id)
#Html.DropDownListFor(m => m.Contact.StateId, new SelectList(Model.States, "Id", "Name", #Model.Contact.StateId))
<input type="submit" value="Save" />
}
}
Try using #Html.DropDownListFor instead, if "state" is a part of your model you can use it like this:
#Html.DropDownListFor(m => m.Contact.StateId, Model.States, "-- Please select a State --") where m.State holds the selected value.
Also not to confuse the IEnumerable with the Model, I would put that in the ViewBag / ViewData.
It would look something like this instead:
#Html.DropDownListFor(m => m.Contact.StateId, (IEnumerable<string>)ViewBag.States, "-- Please select a State --")
And in your action that returns this view you will need to initialize the State enumerable to the ViewBag.States property.

Resources