GetAllUsers - MVC - asp.net-mvc

I’m using the Membership Provider and would like to display a list of all the users and their First Name, Last Name etc using the GetAllUsers function.
I'm having trouble understanding how to implement this function in MVC.
Has anyone implemented this in MVC or is there an easier way to list all the users in my application?
Any help or advise would be really helpful.
Controller
public ActionResult GetUsers()
{
var users = Membership.GetAllUsers();
return View(users);
}
View Model
public class GetUsers
{
[Required]
[DisplayName("User name")]
public string UserName { get; set; }
[Required]
[DisplayName("User name")]
public string FirstName { get; set; }
}
View
<%= Html.Encode(item.UserName) %>
Error
The model item passed into the dictionary is of type 'System.Web.Security.MembershipUserCollection', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Account.Models.GetUsers]'.

View
Inherits="System.Web.Mvc.ViewPage<MembershipUserCollection>"
<ul>
<%foreach (MembershipUser user in Model){ %>
<li><%=user.UserName %></li>
<% }%>
</ul>
Controller
public ActionResult Admin()
{
var users = Membership.GetAllUsers();
return View(users);
}

What's the difficulty you have with it? the GetAllUsers method simply returns a collection of users that you can then display ... either manually, or using a grid component from a vendor like Telerik.
something like:
<% foreach(var user in Membership.GetAllUsers()) { %>
<p>Name: <%= user.UserName %></p>
<% } %>
Obviously, heed the warning in the documentation:
Be careful when using the GetAllUsers
method with very large user databases,
as the resulting
MembershipUserCollection in your
ASP.NET page may degrade the
performance of your application.
There is an overload which lets you do paging to get around this :-)

#Jemes, the problem you're having is that you're passing a System.Web.Security.MembershipUserCollection as the model to your view and you specified that the model of your view was of type Account.Models.GetUsers. Change the type to System.Web.Security.MembershipUserCollection. However, if you're using the default Membership provider in your solution, you will not have the First Name available as the MembershipUser class doesn't have a FirstName property.

Related

Posting back custom collections in ASP.NET MVC2

I have an generic enumerable of type BookCover that I wan't to display to the user. They can only choose one book cover from the selection available.
public class BookCover {
public bool IsSelected { get; set; }
public string CoverPathThumb { get; set; }
public string SpinePathThumb { get; set; }
public string BackPathThumb { get; set; }
}
My action method is similar to
public ActionResult
SelectCover(IEnumerable<BookCover>
covers);
In my template I just enumerate and write out the desired HTML but the problem is I don't know how to get the data from the post back.
How do I name my <input> id's? Is there another reason IEnumerabme isn't populating when the post back occurs?
#Vince: You can customize the ModelBinder. And in the ModelBinder, you can get data from HttpContext.Request.Form, after that you will build your new BookCover collection. Finallly you call
public ActionResult SelectCover(IEnumerable<BookCover> covers);
And remember registering it in Global.asax as:
ModelBinders.Binders[typeof(IEnumerable<BookCover>)] = new YourModelBinderName();
You can get references at here and here is discussion about it. Hope this help you!
You should add an ID you BookCover type, and then use this ID to identify the cover that the user selected. If you retrieve your covers from a database, just use this ID in your class.
I think you can do something like this:
<% foreach(var item in covers) { %>
<%: Html.EditorFor(x => item.IsSelected) %>
<% } %>
The name of your inputs should be in the form:
covers[0].IsSelected
covers[0].CoverPathThumb
covers[0].SpinePathThumb
covers[0].BackPathThumb
E.g.
<input type="text" name="covers[0].CoverPathThumb" />
Increase 0 for each cover entry.

ASP.NET MVC form handling unknown number of inputs

I'm building an internal page that allows trusted users to change a parameter setup manually through a form. The inputs to this setup are a list of setupparameters (of unknown size), each with a specific list of values. The user can then select a value for all or a subset of the parameters.
I have attempted to illustrate this with my current model for the view
public class SetupModel
{
public List<SetupParameter> Parameters { get; set; }
}
public class SetupParameter
{
public string ParameterName { get; set; }
// list with text=paramvalue, value=paramvalueid
public SelectList ParameterValueList { get; set; }
// id of the selected parametervalue if any
public int? SelectedParameterValueID { get; set; }
}
My current attempt at rendering a view for this:
<% using (Html.BeginForm("Update", "Parameters") {%>
...
<% foreach( var parameter in Model.Parameters ) { %>
<div><%: parameter.ParameterName %></div>
<div><%: Html.DropDownListFor(x => parameter.SelectedParameterValueID, parameter.ParameterValueList, "Please select") %></div>
<% } %>
...
My question is how can I render a view that allows me to submit the form and get a reasonably understandable model back to my form action that will allow me to obtain the list of selected parameter values. I'm not aware of the best practices or tricks here, so I will appreciate any feedback I get :)
You could try using a FormCollection:
public ActionResult Submit(FormCollection formCollection)
{
//Iterate form collection to get fields
return View();
}
You might find this post by Phil Haack useful: Model Binding To A List.
Also note that you'll need to post back an identifier (ParameterName, for example) for each parameter too, so you can indentify which value corresponds to a parameter back in the controller.

Posting complex object (with hierarchy) to Controller in ASP.NET MVC

Am using strongly typed view to show a complex object in a data entry/edit form. for eg: Model.UserInformation.Name, Model.LivingPlace.FacilitiesSelectList, Model.Education.DegreesList... etc. These information are shown in multiselect listbox, grids.. etc. User can change the information in the edit screen. Is there any way to post the Model object with user changes to controller on sumbit button click. Please suggest.
Regards,
SHAN
The same object instance that has been passed to the view: No. ASP.NET MVC uses a default Model binder to instantiate new action parameters from request values. So for example if you had the following action method:
public ActionMethod DoWork(User model)
{
return View();
}
public class Address
{
public string Street { get; set; }
}
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Address[] Addresses { get; set; }
}
the binder will look in the request and try to bind model values. You could to the following in your View:
<%= Html.TextBox("FirstName") %>
<%= Html.TextBox("LastName") %>
<%= Html.TextBox("Addresses[0].Street") %>
<%= Html.TextBox("Addresses[1].Street") %>
This will automatically populate the values of your model in the controller action.
To avoid mass assignment of properties that shouldn't be bound from request values it is always a good idea to use the BindAttribute and set Exclude or Include properties.
Use <input type="text" name="UserInformation.Name"><input> to bind to subobjects.

LINQ to SQL how to get value by field name

I use Linq to SQL as data access layer in ASP.NET MVC application. So the query result is a strong typed object. How can I dynamiclly specify which field to show in the page.
For example, the query result has the following fields:
FirstName
LastName
Address
Tel
My question is if one user wanna show the Lastname and the Firstname. 2nd user wanna show the Address and Firstname, 3rd etc... Different user has different requirements. So how can I query the database/filter the result based on user's specific requirement(on demand)?
To be more specific, the query result is a set of person information.
public class Person
{
public string FirstName {get;set;}
public string LastName {get;set;}
public string Tel {get;set;}
public string Tel {get;set;}
}
Take a look at System.Linq.Dynamic:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
1) User indicates in the UI what results the user wishes to see
2) The Controller interprets this and stores this for later
3) The Controller goes to the DAL and gets the data from the DAL
4) The Controller then modifies the return result somehow according to #2
5) The Controller then passes the modified data to the UI
6) The UI renders the data
I think your disconnect starts at 4 and may extend as far as 6.
The fact is that there are literally thousands of ways to do this. Here's one way to do it in amazingly C#-like pseudocode.
First, I'd create a view model that contains information on what I want to display to the user.
Original Linq to Sql (abbreviated):
public class Person
{
public string FirstName {get;set;}
public string LastName {get;set;}
public string Tel {get;set;}
}
My view model:
public partial class PeopleView
{
public bool ShowFirstName {get;set;}
public bool ShowLastName {get;set;}
public bool ShowTel {get;set;}
public IEnumerable<Person> People {get;set;}
}
The controller method that preps the model:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult PersonDetails(bool showFirstName,
bool showLastName, bool showTel)
{
var viewData = new PeopleView()
{
ShowFirstName = showFirstname,
ShowLastName = showLastName,
ShowTel = showTel,
People = Dal.GetPeople()
};
return View(viewData);
}
And here's the View:
<% foreach(var item in ViewData.Model.People){ %>
<% if(ViewData.Model.ShowFirstName) {%>
<%= item.FirstName %><br/>
<% } %>
<% if(ViewData.Model.ShowLastName) {%>
<%= item.LasttName %><br/>
<% } %>
<% if(ViewData.Model.ShowTel) {%>
<%= item.Tel %><br/>
<% } %>
<% } %>
Use an if statement based upon user input. I am assuming you stored the User's preference somewhere, in which case the following code would do the trick:
if (showAddress)
{
var results = from u in Users
select new
{
FirstName = u.FirstName;
LastName = u.LastName;
Address= u.Address;
}
// Code to display results goes here
}
else
{
var results = from u in Users
select new
{
FirstName = u.FirstName;
LastName = u.LastName;
}
// Code to display results goes here
}

Separating two forms in the same view in ASP.Net MVC

I've merged the create account view and the log in view in the same view. So it's a view with two forms, but they get mixed when I submit. If I try to log in and there's an error that is displayed with:
Html.ValidationSummary()
both forms get the error. And I started to rename fields to loginPassword, createPassword, because otherwise when I submit and the password is missing, it's marked as missing on both side.
What would be the way to separate these two forms so they can work indenpendently on the same view/page?
Ah yes, I've had to do exactly this before. The way I found was to set a flag in the ViewData detailing which form was posted and then I created my own extension method for ValidationSummary.
The code isn't with me right now so I'll try my best to do some air code for it now, it's obviously just an concept of how to do it so take it at face value.
To start with I would use the same setup as tvanfosson suggested with his 'EntryPageModel'.
View - note Html.MyValidationSummary
<% using(Html.BeginForm("NewAccount", "Account")) %>
<% { %>
<%= Html.MyValidationSummary("NewAccountForm") %>
<%= Html.TextBox("NewAccount.FirstName") %>
<%= Html.TextBox("NewAccount.LastName") %>
<%= Html.TextBox("NewAccount.Email") %>
<%= Html.Password("NewAccount.Password") %>
<%= Html.Password("NewAccount.ConfirmPassword") %>
<% } %>
<% using(Html.BeginForm("Login", "Account")) %>
<% { %>
<%= Html.MyValidationSummary("LoginForm") %>
<%= Html.TextBox("Login.Email") %>
<%= Html.Password("Login.Password") %>
<% } %>
Controller - note ViewData["PostedForm"]
public class Account : Controller
{
private EntryPageModel _viewModel;
public ActionResult NewAccount(FormCollection formValues)
{
try
{
//binding and validation for _viewModel.NewAccount
}
catch
{
ViewData["PostedForm"] = "NewAccountForm";
return View("RegisterAndLogin", _viewModel);
}
}
public ActionResult Login(FormCollection formValues)
{
try
{
//binding and validation for _viewModel.Login
}
catch
{
ViewData["PostedForm"] = "LoginForm";
return View("RegisterAndLogin", _viewModel); //You'll want to pass in a model
}
}
}
Custom html extension
namespace System.Web.Mvc
{
public static class HtmlExtensions
{
public static string MyValidationSummary(this HtmlHelper html, string formName)
{
if (!string.IsNullOrEmpty(html.ViewData["PostedForm"])
&& (html.ViewData["PostedForm"] == formName))
{
return html.ValidationSummary();
}
return "";
}
}
}
HTHs,
Charles
I had to deal with the same problem. I found that there is no way to separate the validation messages using the built in ValidationSummary(). Here are two suggestions:
Position the validation summary in an area where it could apply to both forms. For example, if the login and sign up forms are side by side, position the validation summary in a div centered above both forms. I found an example of this style on the Mahalo login page.
In the appropriate controller action methods, add something to the ViewData indicating which action was called. In the view there will be a ValidationSummary for each form, but each will be conditionally rendered based on what you added to the ViewData.
Either way the form fields should be uniquely named.
I went with solution #1 because I was satisfied with the way I was able to get it to look. But if you need the validation summary to appear in two different locations depending on which form was submitted, go with #2.
The input elements do need different names/ids even if they are in different forms. Unless they have different names, it will trigger the validation logic for each control since it matches based on the name of the control. I think you are on the right track by changing the names to differentiate them.
I'd set it up with a compound model, perhaps so that you could do something like (note this is incomplete):
<%= Html.TextBox( "Login.Name" ) %>
<%= Html.TextBox( "Login.Password" ) %>
<%= Html.TextBox( "NewAccount.Name" ) %>
<%= Html.TextBox( "NewAccount.Password" ) %>
<%= Html.TextBox( "NewAccount.ConfirmPassword" ) %>
On the server side, use the prefix option for the binder
public ActionResult Login( [Bind(Prefix="Login")]AccountModel model )
{
...
}
And your model would look like:
public class AccountModel
{
public string Name { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
public class EntryPageModel
{
public AccountModel Login { get; set; }
public AccountModel NewAccount { get; set; }
}
If the forms are posting to completely different actions, then your ModelStateDictionary should only contain the errors that were provided by the action that was invoked.
Can you post the relevant code?
I'm not sure if there is a way to split the ValidationSummary().
For your forms, you could create model classes that you would bind against, with the various fields. It wouldn't gain you much over what you've already got, though.

Resources