Roles Provider - AccountModel - asp.net-mvc

I'm adding the Roles provider to the built in AccountModel but having some problems adding GetAllRoles in my view using the Register View Model.
View Model from AccountModel
public class RegisterModel
{
UserName, Email Etc....
[Required]
[DisplayName("AllRoles")]
public SelectList AllRoles { get; set; }
}
Roles Service added to AccountModel
public interface IRolesService
{
SelectList GetAllRoles();
}
public class RolesService : IRolesService
{
public SelectList GetAllRoles()
{
var AllRoles = new SelectList(Roles.GetAllRoles());
return AllRoles;
}
}
Register View Page Inherits RegisterModel
Form...
<div class="editor-label">
<%= Html.LabelFor(m => m.ConfirmPassword) %>
</div>
<div class="editor-field">
<%= Html.PasswordFor(m => m.ConfirmPassword) %>
<%= Html.ValidationMessageFor(m => m.ConfirmPassword) %>
</div>
<%= Html.DropDownListFor(m => m.AllRoles)%>
I'm not sure how to populate the DropDown list with all the Roles from the View Model.
Any help would be really great!!

I think you need properties for the selected role and the full list of roles. The list of roles will be used to populate the dropdown, the selected role will be populated on post with the selected value.
public class RegisterModel
{
UserName, Email Etc....
[Required]
[DisplayName("Role")]
public string Role { get; set; }
[ScaffoldColumn(false)]
public SelectList AllRoles { get; set; }
}
...
public ActionResult Register()
{
var roleService = new RoleService();
var model = new RegisterModel
{
AllRoles = roleService.GetAllRoles(),
// Role = "User" if you want to choose a default
}
return View( model );
}
<div class="editor-label">
<%= Html.LabelFor(m => m.ConfirmPassword) %>
</div>
<div class="editor-field">
<%= Html.PasswordFor(m => m.ConfirmPassword) %>
<%= Html.ValidationMessageFor(m => m.ConfirmPassword) %>
</div>
<%= Html.DropDownListFor(m => m.Role, Model.AllRoles, "--select--", null )%>

Related

MVC Dropdown list null on view on submit

I'm having issues with drop down lists on MVC. I've searched and searched but to no avail.
My ViewModel
public class IncidentFormViewModel
{
public Guid Guid { get; set; }
public Incident Incident { get; set; }
public Guid PersonInvolvedId { get; set; }
public IEnumerable<Person> People { get; set; }
}
My Controller
public ActionResult New()
{
var incidentFormVM = new IncidentFormViewModel
{
Incident = new Incident(),
People = unitofwork.Person.GetAll()
};
return View("IncidentForm", incidentFormVM);
}
and View(I've taken out useless information)
#using (Html.BeginForm("Save", "Incident"))
<div class="container">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
#Html.LabelFor(m => m.Incident.PersonInvolved)
#Html.DropDownListFor(m => m.PersonInvolvedId, new SelectList(Model.People, "Id", "FirstName"), new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Incident.PersonInvolved)
</div>
</div>
<br />
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
The thing is if i put a stop on the line below and put a watch on Model.People i can see the list of people against it.
#Html.DropDownListFor(m => m.PersonInvolvedId, new SelectList(Model.People, "Id", "FirstName"), new { #class = "form-control" })
What am i doing wrong?

Customizing UserProfile class SimpleMembershipProvider

I am new to MVC and I am trying to build a small test application to get a clear idea about how the SimpleMembershipProvider works in MVC 4. I have created two Roles - Student and Teacher. I have only one user with Teacher Role assigned(hard coded in Configuration.cs), who is going to create Students and while creating a new student, the Teacher will also generate the UserID and password for that student.The newly created student will then log on to the application with the userid and password as created by the Teacher and will do certain tasks.
The problem is whenever the user with Teacher Role creates a student, the current logged in user with Teacher Role gets logged out and the newly created student gets logged in. What I have done is, I have not kept any field for userid and password in Student Model. I have used a partial view bound to RegisterModel(from AccountModels) to generate the fields for Username and password while creating new Student. I have kept StudentID in UserProfile Model.
This is my code as shown below for further clarity.
Student Model
public class Student
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[DisplayName("First Name")]
public string FirstName { get; set; }
[DisplayName("Last Name")]
public string LastName { get; set; }
[DisplayName("Date of Birth")]
public string DateOfBirth { get; set; }
public Gender Gender { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
UserProfile Model
public class UserProfile
{
public int UserId { get; set; }
public string UserName { get; set; }
public int StudentId { get; set; }
}
This is from Configuration.cs where I am creating the Roles and a user with Teacher Role
private void SeedMemebership()
{
WebSecurity.InitializeDatabaseConnection("DefaultConnection1",
"UserProfile", "UserId", "UserName", autoCreateTables: true);
var roles = (SimpleRoleProvider)Roles.Provider;
var membership = (SimpleMembershipProvider)Membership.Provider;
if (!roles.RoleExists("Teacher"))
{
roles.CreateRole("Teacher");
}
if (!roles.RoleExists("Student"))
{
roles.CreateRole("Student");
}
if (membership.GetUser("UserFoo", false) == null)
{
membership.CreateUserAndAccount("UserFoo", "Password");
}
if (!roles.GetRolesForUser("UserFoo").Contains("Teacher"))
{
roles.AddUsersToRoles(new[] { "UserFoo" }, new[] { "Teacher" });
}
}
Controller Actions To Create Student-
//
// GET: /Student/Create
[Authorize(Roles = "Teacher", Users = "UserFoo")]
public ActionResult Create()
{
return View();
}
//
// POST: /Student/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Student student, RegisterModel model)
{
if (ModelState.IsValid)
{
try
{
db.Students.Add(student);
db.SaveChanges();
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { StudentId = student.Id });
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Student");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
return View(student);
}
Corresponding Views -
#model TestApp.Models.Student
#{
ViewBag.Title = "Create";
}
<script type="text/javascript" src="~/Scripts/MyCustom.js"></script>
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Student</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DateOfBirth)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DateOfBirth)
#Html.ValidationMessageFor(model => model.DateOfBirth)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Gender)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Gender, new SelectList(Enum.GetValues(typeof(TestApp.Models.Gender))))
#Html.ValidationMessageFor(model => model.Gender)
</div>
<div class="float-right-top">
#Html.Partial("_PartialRegisterStudent")
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Partial View "_PartialRegisterStudent.cshtml
#model TestApp.Models.RegisterModel
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset>
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
</li>
<li>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
</li>
<li>
#Html.LabelFor(m => m.ConfirmPassword)
#Html.PasswordFor(m => m.ConfirmPassword)
</li>
</ol>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
What will be the best way to create students with Teacher Role without the logged in user logging out of the application? I thought about using inheritance(Parent - UserProfile, Child-Student) and one to one relationship between student model and userprofile model but could not make out how to make it work. Code Samples will be very much appreciated!
P.S. Parden me if this post is a bit lengthy. Thank you.
Just delete below line in Create Action, it should work.
WebSecurity.Login(model.UserName, model.Password);

Custom view control for MVC doesn't work?

I have the following custom view control in MVC. However, it doesn't work at all.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>" %>
<%=Html.TextBox("", (Model.HasValue ? Model.Value.ToShortDateString() : string.Empty), new { #class = "timePicker" }) %>
And this is where I use it from, and how:
<div class="editor-field">
#Html.EditorFor(model => model.StartTime)
#Html.ValidationMessageFor(model => model.StartTime)
</div>
The model looks like this:
[Bind()]
[Table("DailyReports", Schema = "Actives")]
public class DailyReport
{
[Key()]
[Display(AutoGenerateField = false, AutoGenerateFilter = false)]
public int ID { get; set; }
[DisplayName("Starttidspunkt")]
public DateTime? StartTime { get; set; }
[DisplayName("Sluttidspunkt")]
public DateTime? EndTime { get; set; }
[DisplayName("Time-rapporter")]
public virtual ICollection<HourlyReport> HourlyReports { get; set; }
public DailyReport()
{
}
}
However, a simple textfield just shows up, when in reality, I expect the view user control to show up, since the type is DateTime.
Any suggestions on how to solve this?
I'm assuming that you're correctly placing your template in the EditorTemplates folder, and that you're naming it after the correct type (ie DateTime.aspx)
Beause you're using a nullable type, you need to specify the template name manually.
<%: Html.EditorFor(model => model.StartTime, "NullableDateTimeTemplate" )%>
Or, you can check the model metadata to determine if the type is nullable.
<% if (ViewData.ModelMetadata.IsNullableValueType) { %>
<%= Html.TextBox("", (Model.HasValue ? Model.Value.ToShortDateString() : string.Empty),
new { #class = "timePicker" }) %>
<% } else { %>
<%= Html.TextBox("", Model.ToShortDateString(), new { #class = "timePicker" }) %>
<% } %>

ASP.NET MVC 2 edit controller doesn't work using viewmodel

Hey, the problem is that edit controller in ASP.NET MVC 2 doesn't work. I tried many ways and nothing works.
Here's a sample code:
[Authorize]
public ActionResult Edit() {
var edit = new UserViewModel {
User = Database.Users.Single(u => u.UserName == User.Identity.Name)
};
return View(edit);
}
[Authorize]
[HttpPost]
public ActionResult Edit(FormCollection formCollection) {
var edit = new UserViewModel {
User = Database.Users.Single(u => u.UserName == User.Identity.Name)
};
// TODO: try, catch
UpdateModel(edit, "User");
Database.SaveChanges();
return View(edit);
}
Here's a view model class:
public class UserViewModel {
public User User { get; set; }
}
What should I do to update this user model to database? A the moment I'm using only Email field:
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) {%>
<div>
<div class="UserFieldLeft"><%: Html.LabelFor(model => model.User.Email) %></div>
<div class="UserFieldRight"><%: Html.TextBoxFor(model => model.User.Email, new { style="width: 200px" }) %></div>
<div class="UserFieldHelper"><%: Html.ValidationMessageFor(model => model.User.Email) %></div>
<p><input class="UserFieldInput" type="submit" value="ZmieƄ email" /></p>
</div>
<% } %>
If I work on native user model it doesn't work too. What's wrong? Where did I made a mistake?
By the way, I've to use view model to add (in future) some checkboxes (hair color, length, etc.) to my user.
Thank you for your time and help.
You don't need the prefix "User".
UpdateModel(edit);
should work. In the formsCollection their should be a key with User.Email. This should map to the Email property in the User Object.

Validating a SelectList in ASP.NET MVC 2 with Data Annotations

I'm trying to use the built in ASP.NET MVC 2 client side validation on a Select List like the following:
private SelectList _CategoryList;
[Required(ErrorMessage = "Category Required")]
[System.ComponentModel.DataAnnotations.Range(1, double.MaxValue, ErrorMessage = "Please Select A Category")]
[DisplayName("Category")]
public SelectList CategoryList
{
get
{
return new SelectList(Categories, "CatID", "CatFullName"); ;
}
set
{
_CategoryList = value;
}
}
However it's not working...if the default value which is 0 is selected the validation message does not appear and the page progresses as though it's validated. Thoughts?
Ok so I found the answer in an answer to a slightly different question. So I'm posting my complete code here, which extends on Scott Guthries ASP.NET MVC 2 Validation post: http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx
My ViewModel:
public class Person
{
[Required(ErrorMessage="First Name Required")]
[StringLength(50,ErrorMessage="Must be under 50 characters")]
public string FirstName { get; set; }
[Required(ErrorMessage="Last Name Required")]
[StringLength(50, ErrorMessage = "Must be under 50 characters")]
public string LastName { get; set; }
[Required(ErrorMessage="Age Required")]
[Range(1,120,ErrorMessage="Age Must be between 0 and 120")]
public int Age { get; set; }
[Required(ErrorMessage="Email Required")]
public string Email { get; set; }
public IEnumerable<SelectListItem> FavoriteColor { get; set; }
[Range(0, 6, ErrorMessage = "Out of range")]
public int SelectedFavColor { get; set; }
}
My Color class:
public class Colors
{
public int ColorID { get; set; }
public string ColorName { get; set; }
}
My list helper extensions stolen from Rob Connery, who stole it from someone else:
public static class ListExtensions
{
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
foreach (var item in collection) action(item);
return collection;
}
public static SelectList ToSelectList<T>(this IEnumerable<T> collection)
{
return new SelectList(collection, "Key", "Value");
}
public static SelectList ToSelectList<T>(this IEnumerable<T> collection, string selectedValue)
{
return new SelectList(collection, "Key", "Value", selectedValue);
}
public static SelectList ToSelectList<T>(this IEnumerable<T> collection,
string dataValueField, string dataTextField)
{
return new SelectList(collection, dataValueField, dataTextField);
}
public static SelectList ToSelectList<T>(this IEnumerable<T> collection,
string dataValueField, string dataTextField, string selectedValue)
{
return new SelectList(collection, dataValueField, dataTextField, selectedValue);
}
}
My Controller Code (yes it could be refactored to be more DRY):
public ActionResult Create()
{
Person newFriend = new Person();
IList<Colors> colorslist = new List<Colors>();
colorslist.Add(new Colors { ColorID = -1, ColorName = "Please Select Color" });
colorslist.Add(new Colors { ColorID = 1, ColorName = "Red" });
colorslist.Add(new Colors { ColorID = 2, ColorName = "Green" });
colorslist.Add(new Colors { ColorID = 3, ColorName = "Blue" });
newFriend.FavoriteColor = colorslist.ToSelectList("ColorID","ColorName","-1");
return View(newFriend);
}
[HttpPost]
public ActionResult Create(Person friendToCreate, FormCollection collection)
{
friendToCreate.SelectedFavColor = Convert.ToInt32(collection["SelectedFavColor"]);
if (ModelState.IsValid)
{
return Redirect("/");
}
IList<Colors> colorslist = new List<Colors>();
colorslist.Add(new Colors { ColorID = -1, ColorName = "Please Select Color" });
colorslist.Add(new Colors { ColorID = 1, ColorName = "Red" });
colorslist.Add(new Colors { ColorID = 2, ColorName = "Green" });
colorslist.Add(new Colors { ColorID = 3, ColorName = "Blue" });
friendToCreate.FavoriteColor = colorslist.ToSelectList("ColorID", "ColorName");
return View(friendToCreate);
}
My page markup:
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%= Html.LabelFor(model => model.FirstName) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.FirstName) %>
<%= Html.ValidationMessageFor(model => model.FirstName) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.LastName) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.LastName) %>
<%= Html.ValidationMessageFor(model => model.LastName) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.Age) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Age) %>
<%= Html.ValidationMessageFor(model => model.Age) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.Email) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Email) %>
<%= Html.ValidationMessageFor(model => model.Email) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.FavoriteColor) %>
</div>
<div class="editor-field">
<%= Html.DropDownList("SelectedFavColor", Model.FavoriteColor, -1)%>
<%= Html.ValidationMessageFor(model => model.SelectedFavColor) %>
</div>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
<% } %>
When I work with my ViewModel, I'd have a property CategoryId and put my range validator on that, not the dropdown. The Selectlist just provides the data - you validate against the model.
[Required(ErrorMessage = "Category Required")]
[System.ComponentModel.DataAnnotations.Range(1, double.MaxValue, ErrorMessage = "Please Select A Category")]
[DisplayName("Category")]
public int CategoryId {get;set;}
On the view I'd have my dropdown with the id for my category but the list from my Categories:
<%= Html.DropDownList("CategoryId", (SelectList)Model.Categories, "(Select)")%>
when your data posts back to the server, you should observe that the class contains the id value.
I don't think it has to do with DataAnnotations because it happens without them as well when you have a model bound to an entity with a non-nullable and you try to put an invalid value in. What I have done is to send along ModelState["XXXX"].Value.AttemptedValue from the form and validate against that instead of the property in the entity. I wonder if validating against the raw form data entirely instead of just the problem items is more appropriate.
A similar reply: ASP.NET MVC: DataAnnotations - Show an error message indicating that a field must be numeric
I also posed a similar question: ASP.NET MVC. Validation fails on dropdown no matter the value

Resources