I'm relatively new to MVC, and I kicked off with the default MVC project template in visual studio 2013 (Express).
I modified the views to suit my needs (temporarily), then followed this tutorial to add 3 new fields to the user registration process. I added BirthDate and Email as in the tutorial, and a third one: FirstName. Everything built and published fine.
After this, I uploaded the published site to my domain here and tested in Chrome. All of the pages load correctly, but when I try to register a user, I get taken to the "Error" page. I've checked the JS console and the only entry is: event.returnValue is deprecated. Please use the standard event.preventDefault() instead.
Here is the code for my C# classes as shown in the tutorial above:
Account/Register View (New fields):
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.FirstName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">#Html.TextBoxFor(m => m.FirstName, new { #class = "form-control" })
</div>
Account ViewModel (Register ViewModel New Fields):
[Required]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
[Required]
[Display(Name = "Email Address")]
public string Email { get; set; }
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
Identity Model (ApplicationUser Method):
public class ApplicationUser : IdentityUser
{
public DateTime BirthDate { get; set; }
public string Email { get; set; }
public String FirstName { get; set; }
}
Account Controller (Post:Register Method):
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName, BirthDate = model.BirthDate, Email = model.Email, FirstName = model.FirstName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Please could you let me know if you think you know what is causing the error page (I'll leave it live so you can see for yourself) or if you know how I can find out the specific error. Any help will be greatly appreciated. Thanks.
Update 1: I get taken to the same error pag on logging in rather than being told a username is not in database. Is this meant to happen?
Update 2: It runs fine locally.
Related
I want to use remote validation to check to see if a Username exists. I am using a Viewmodel to create users. While I can do this to get validation for creation or editing purposes, it will not work for both creating and editing. Here is my model:
[Required]
[Display(Name = "Homeowner Username")]
[Remote("doesUserNameExist", "Homeowners", HttpMethod = "POST", ErrorMessage = "User name already exists. Please enter a different user name.", AdditionalFields = "InitialUsername")]
Here is my edit view:
#Html.Hidden("Homeowner.InitialUsername", Model.Username)
<div class="form-group">
#Html.LabelFor(model => model.Username, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Username, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Username, "", new { #class = "text-danger" })
</div>
</div>
Here is my controller in the version that works for registration but not editing(when editing, parameters are null):
public JsonResult doesUserNameExist([Bind(Prefix = "Homeowner.Username")]string Username, [Bind(Prefix = "InitialUsername")] string InitialUsername)
{
MY CODE
}
Here is my controller that works for editing but not creating(when creating, both parameters are null):
public JsonResult doesUserNameExist([Bind(Include = "Homeowner.Username")]string Username, [Bind(Include = "InitialUsername")] string InitialUsername)
{
MY CODE
}
I have tried many variations of this but just can't get it.
I have looked here: ASP.NET MVC Binding with Remote Validation
Here:
Remote ViewModel validation of nested objects not working
And here: http://forums.asp.net/t/1652512.aspx?Compound+View+Model+object+causing+remote+validation+failure
But I seem to be missing something. Is there a way I can make this work for both editing and registering? I am pretty new at this, and would greatly appreciate any ideas!
Edit:
Perhaps this is a poor design choice(first time using view models, only been coding a few months), but I was trying to create a new homeowner and address at the same time as when I create a new application user in that role. Here is the viewmodel I am using:
public class RegisterHomeownerViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public int roles { get; set; }
public virtual Address Address { get; set; }
public virtual Homeowner Homeowner { get; set; }
}
Here is my method in the account controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> RegisterHomeowner(RegisterHomeownerViewModel model, Address address, Homeowner homeowner)
{
ApplicationDbContext db = new ApplicationDbContext();
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var role = db.Roles.Find("0");
UserManager.AddToRole(user.Id, role.Name);
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
db.Addresses.Add(address);
homeowner.UserId = user.Id;
homeowner.AddressID = address.ID;
db.Homeowners.Add(homeowner);
db.SaveChanges();
return RedirectToAction("Index", "Homeowners");
}
AddErrors(result);
}
return View(model);
}
Here is the view I am using to create those entities:
<div class="form-horizontal">
<h4>RegisterViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Homeowner.Username, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Homeowner.Username, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Homeowner.Username, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
</div>
</div>
Everything does work as far as I can tell except for remote validation on Username. I can get it to give me an error when creating in the account method above, or I can get an error when editing by deleting the Prefix (which makes it so my Username is not recognized. There is obviously something I am doing wrong.
I got it. I read Stephen's post a few times and a few threads on virtual properties. I went to bed, got up, and revised my viewmodel by removing all data models. Then, for validation when creating, I compared the input to the validation properties in my view model instead of my actual model. This works for creation. Then when I edit, I compare my input against the validation properties in my actual model. It made sense when I learned you can have different validation for a viewmodel than there is in the model. This thread helped too: View Model virtual properties and drop down lists. Thanks so much! I learned a lot from this!
im new in asp.net mvc. i watch a tutorial and he is using webmatrix. i tried to add column named "IDViewer" in table "UserProfile" in my database created by webmatrix. but then, when i tried to insert some value it returns me an error of "Invalid column name 'Length'." but i did not declare column name "Length" in my code. please check my codes and the images. thank you
Images Link Here. please take a look
The error
My database, i added column named IDViewer
public class Register
{
[Required(ErrorMessage = "Please provide password", AllowEmptyStrings = false)]
public string Username { get; set; }
[Required(ErrorMessage = "Please provide password", AllowEmptyStrings = false)]
[DataType(System.ComponentModel.DataAnnotations.DataType.Password)]
[StringLength(50, MinimumLength = 8, ErrorMessage = "Password must be 8 char long.")]
public string Password { get; set; }
public string IDViewer { get; set; }
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary("", new { #style = "color: red" })
<label>Username</label>
#Html.TextBoxFor(m => m.Username, new { #class = "form-control" })
<label>Password</label>
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
<label>Student ID</label>
#Html.TextBoxFor(m => m.IDViewer, new { #class = "form-control" })
#Html.DropDownList("role",roles,"Select Account Type")
<button class="btn btn-primary">Register</button>
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(Register registerdata, string role)
{
if(ModelState.IsValid)
{
try
{
WebSecurity.CreateUserAndAccount(registerdata.Username, registerdata.Password, registerdata.IDViewer);
Roles.AddUserToRole(registerdata.Username,role);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException)
{
ModelState.AddModelError("", "Sorry the username already exists");
return View(registerdata);
}
}
ModelState.AddModelError("","Data invalid");
return View(registerdata);
}
From the documentation, the 3rd parameter is a dictionary
propertyValues
Type: System.Object
(Optional) A dictionary that contains additional user attributes. The default is null.
so your method needs to be
WebSecurity.CreateUserAndAccount(registerdata.Username,
registerdata.Password, new { IDViewer = registerdata.IDViewer });
I'm implementing an ASP.NET MVC web application just for fun. In my application, users can log in and join groups. I have a user authentication which works, where I inherit the identityUser. But I'd also like to authenticate the groups, i.e. if user tries to join a group, he would have to know the groups password to be able to join the group.
The entity model for the groups is like that:
public int Id { get; set; }
public string groupName { get; set; } <-- this is unique
public string Password { get; set; }
The view model would be similar but with [Required] attribute and what follows the View model.
But what I'm having trouble with is how I can authenticate the groups, have the passwordhash and check if password is valid and so on?
I'm using Visual Studio 2015.
My view when registering group:
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</div>
</div>
My group view model:
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
Then I'm wondering how the controller should be so it'll authenticate the group.
[HttpPost, Authorize]
public ActionResult CreateLeague(RegisterGroupViewModel model)
{
if (!ModelState.IsValid) return View(model);
// check here if password is okay, and also hash it <-- here is my problem
// I've implemented if group is free to create, and create the group in the database.. which would be here below, no need to show it here.
}
I'm very new to MVC 5 and web programming in general so please bear with me.
I have a view (used to manage user roles) where I have three separate forms, which I more or less copied and pasted from a tutorial. In the tutorial the fields for the forms were created in the following way:
Username : #Html.TextBox("Username")
Since I wanted the styling to work for them, I changed the code to look more like the default forms in the MVC 5 template, so it ended up looking like this:
#Html.LabelFor(m => m.GetRolesUsername, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.GetRolesUsername, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.GetRolesUsername, "", new { #class = "text-danger" })
</div>
My model ManageUserRolesViewModel looks like this (note that at the top of my view I have #model ManageUserRolesViewModel):
public class ManageUserRolesViewModel
{
#region Assign Role
[Required]
[Display(Name = "Username", ResourceType = typeof(Resources))]
public string AssignRoleUsername { get; set; }
[Required]
[Display(Name = "RoleName", ResourceType = typeof(Resources))]
public string AssignRoleRole { get; set; }
#endregion
#region Get Roles
[Required]
[Display(Name = "Username", ResourceType = typeof(Resources))]
public string GetRolesUsername { get; set; }
#endregion
#region Unassign Role
[Required]
[Display(Name = "Username", ResourceType = typeof(Resources))]
public string UnassignRoleUsername { get; set; }
[Required]
[Display(Name = "RoleName", ResourceType = typeof(Resources))]
public string UnassignRoleRole { get; set; }
#endregion
}
Notice how I'm using annotations to load the name of the elements in the ViewModel directly from resources. I'm doing this for localization purposes, and the resources are returning strings in Spanish. I think this may be the root of my issue, but I'm not sure.
Then, in my controller I have the following method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult GetRoles(string UserName)
{
if (!string.IsNullOrWhiteSpace(UserName))
{
ApplicationUser user = context.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
ViewBag.RolesForThisUser = this.UserManager.GetRoles(user.Id);
ViewBag.Roles = context.Roles.OrderBy(r => r.Name).ToList().Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();
}
return View("ManageUserRoles");
}
Now, here's what happens: if I use Username : #Html.TextBox("Username"), when the method GetRoles() gets called in the controler, the UserName parameter is there and the user is successfully loaded. If instead I use the
#Html.LabelFor(m => m.GetRolesUsername, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.GetRolesUsername, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.GetRolesUsername, "", new { #class = "text-danger" })
</div>
when the method gets called, the UserName parameter is null.
My wild guess is that somewhere in the code MVC is looking for UserName or Username and finding Usuario instead, but I am not sure if this is true and in any case, I'd like to know how to solve the issue.
Assuming your form has the model defined as:
#model ManageUserRolesViewModel
and somewhere in the view:
#Html.TextBoxFor(m => m.GetRolesUsername, new { #class = "form-control" })
The action should look like this:
[HttpPost]
public ActionResult GetRoles(ManageUserRolesViewModel vm)
{
string userName = vm.GetRolesUsername;
//rest of code omitted.
}
So you do not rely on the UserName parameter and can use the view model itself.
if this does not suffice, you could do this:
#Html.TextBoxFor(x => x.GetRolesUsername, new { Name = "UserName" })
Hi Eric,
#Html.TextBox("Username")
// It creates a html input element with name "Username"
<input type="text" id=""Username" name="Username" value="" />
And
#Html.TextBoxFor(m => m.GetRolesUsername)
// It also create a html element with name as it's property name. ie, "GetRolesUsername"
<input type="text" id=""Username" name="Username" value="#Model.GetRolesUsername" />
So, if you submit your form, your browser will send parameters as,
Username = "value in the #html.TeaxtBox()",
GetRolesUsername = "value in the #html.TextBoxFor()"
So, both values will be passed to your MVC controller. Then you can decide what parameters you want to receive.
public ActionResult Submit(string Username, string GetRolesUsername)
{
// You can get Username and GetRolesUsername here
}
public ActionResult Submit(string Username)
{
// You tell your controller that I am expecting only one parameter and that is Username
}
Then there will be a main difference between `#html.TextBox()` and `#html.TextBoxFor()' is,
`#html.TextBox()` will just create a text element. But, `#html.TextBoxFor()' will create and set value to the element.
Hope this will help you.
If you have any doubts, please feel free to ask me.
**And Grand Welcome To MVC.**
I am also just a beginner in MVC :)
I am using the ASP.NET web application template and trying to allow a user to pick a role when registering.
Here is what I got at the moment.
Does it
View
<fieldset class="col-lg-5 .col-md-5">
<legend>Registration Form</legend>
<p>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control" })
</p>
<p>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</p>
<p>
#Html.LabelFor(m => m.ConfirmPassword)
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</p>
<p>
#Html.DropDownListFor(model => model.Type, Model.TypeList)
</p>
<input type="submit" value="Register" class="btn btn-default" />
</fieldset>
Model
public class RegisterModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public string Type { get; set; }
public IEnumerable<SelectListItem> TypeList
{
get
{
return new List<SelectListItem>
{
new SelectListItem { Text = "athlete", Value = "athlete"},
new SelectListItem { Text = "coach", Value = "coach"},
};
}
}
}
Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
Roles.AddUserToRole(model.UserName, model.Type);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
I am feel like I am close but I can't quiet get it and i am getting this error
Compiler Error Message: Models.RegisterModel>' does not contain a definition for 'DropDownListFor' and the best extension method overload 'System.Web.Mvc.Html.SelectExtensions.DropDownListFor(System.Web.Mvc.HtmlHelper, System.Linq.Expressions.Expression>, System.Collections.Generic.IEnumerable)' has some invalid arguments
Did you initialize your model in HttpGet Register method? Like below...
[AllowAnonymous]
public ActionResult Register()
{
var model = new RegisterModel();
return View(model);
}
I create an empty template MVC4 app, added your code, got object reference not set error as default Register model does not pass model object to view which you are trying to access (i.e. loading TypeInt in DropDownListFor()).
I then initialized model in Get method as shown above. All works fine, i was able to pick a role on register view.
Check if this helps.
take a look your last comma should be removed:
new SelectListItem { Text = "athlete", Value = "athlete"},
new SelectListItem { Text = "coach", Value = "coach"}