I have been working on a projectbased on mvc5.
I applied a form validation on my Model class. The "compare" condition is applied User_password and User_Password_Confirm. It works perfectly on insertion. But when I have to update the information of same client bt not password, in this case my MoldeStat.Valid is "false" because I think it is because of "compare" condition on password.
Can someone tell me how Can i solve this issue?
I am facing a problem with "update".
Thank you for your help in advance
my Model class
[Required(ErrorMessage = "*")]
public string User_Password { get; set; }
[Compare("User_Password")]
[Required(ErrorMessage = "*")]
public string User_Password_Confirm { get; set; }enter code here
My controller class
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit2([Bind(Include = "User_Id,User_Nom,User_Prenom,User_Email,User_Telephone,User_Role,User_Password,User_Password_Confirm,UserCreationDate,User_Status")] User user)
{
if (ModelState.IsValid)
{
//db.Entry(user).State = EntityState.Modified;
//db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.User_Status = new SelectList(db.Account_Status, "Account_Status_ID", "Account_Status_Nom", user.User_Status);
ViewBag.User_Role = new SelectList(db.Role, "Role_Id", "Role_Name", user.User_Role);
return View("edit");
}
View of insert (just password section). Here I tried to set value of User_Password_confirm = User_password but it failed :(
<div class="form-group">
#Html.LabelFor(model => model.User_Password, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.User_Password)
#Html.ValidationMessageFor(model => model.User_Password)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.User_Password_Confirm, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.User_Password_Confirm, new { #Value = Model.User_Password })
#Html.ValidationMessageFor(model => model.User_Password_Confirm)
</div>
</div>
First, i suggest you to create two different models : UserCreateModel and UserUpdateModel for example.
Then your code will include some security breach.
if i'm user Id 275, i can change the userId in the form (even if it's hidden), this way i'm gonna be able to change email, password, firstname, lastname of any user.
What you need to do is get the Id of the logged user and change only the data that has been changed.
if (ModelState.IsValid)
{
var userfromDb = db.Users.Find(loggedUser.EmployeeId);
userfromDb .Email = user.Email;//etc...
db.SaveChanges();
return RedirectToAction("Index");
}
You may easily see a summary of all model validation errors by inserting a
#Html.ValidationSummary
on your view.
Related
I have the Model which contains the few properties. There are List<Point> and ThranslatingCam. The ThranslatingCam contains property which should be entered by the user.
public class TranslatingCamModel
{
public TranslatingCam Cam { get; set; }
public List<Point> Points { get; set; }
}
Now I use the Points just for visualization but in future this list will be changed by user.
In the Controller I initialize the Points list, add it to my TranslatingCamModel and send it to the View.
public ActionResult Cam()
{
TranslatingCamModel model = new TranslatingCamModel();
List<Points> points = new List<Points>();
//here I add same data to the points list
model.Points = points;
model.Cam = new TranslatingCam();
return View("TranslatingCam", model);
}
This code works as I want. My problem is further.
#model CamShaft.WebUI.Models.TranslatingCamModel
#{
ViewBag.Title = "Cam";
}
<div class="prop">
#using (Html.BeginForm("DrawTranslatingCam", "Home"))
{
#Html.LabelFor(model => model.Cam.Rmin, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.Cam.Rmin, new { htmlAttributes = new { #class = "form-control" } })
//And the same for the other Cam's properties
<input type="submit" value="Draw" />
}
</div>
//Here is my code for visualization and etc... And here I can work with the model.Points.
It works okay too, I get value for Cam but I lose my Points list.
public ActionResult DrawTranslatingCam(TranslatingCamModel model)
{
//Here I have model returned from the View
}
Here is model.Cam with entered by user data but model.Points list is null. But I initialized it before I sent it to the View..
I tried to solve using #Html.HiddenFor:
#using (Html.BeginForm("DrawTranslatingCam", "Home"))
{
#Html.LabelFor(model => model.Cam.Rmin, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.Cam.Rmin, new { htmlAttributes = new { #class = "form-control" } })
//And the same for the other Cam's properties
#Html.HiddenFor(model => model.Points)
<input type="submit" value="Draw" />
}
In this case is returned Points list but without date (not null, just with count = 0)
So, how right I can get my Model from the View?
The code has been slightly modified for compactness and clarity.
I have created a controller with views using Entity Framework.Everything works fine but I need to edit users password and I don't have such option,only passwordHash.
How can I do it?
Here is the code of UsersController:
public ActionResult Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ApplicationUser applicationUser = db.Users.Find(id);
if (applicationUser == null)
{
return HttpNotFound();
}
return View(applicationUser);
}
// POST: Users/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Email,EmailConfirmed,PasswordHash,Password,SecurityStamp,PhoneNumber,PhoneNumberConfirmed,TwoFactorEnabled,LockoutEndDateUtc,LockoutEnabled,AccessFailedCount,UserName")] ApplicationUser applicationUser)
{
if (ModelState.IsValid)
{
db.Entry(applicationUser).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(applicationUser);
}
And here is Edit.shtml:
<div class="form-group">
#Html.LabelFor(model => model.PasswordHash, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PasswordHash, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PasswordHash, "", new { #class = "text-danger" })
</div>
</div>
If I try the same with model.Password I have a mistake :
The type arguments for method
'System.Web.Mvc.Html.LabelExtensions.LabelFor(System.Web.Mvc.HtmlHelper,
System.Linq.Expressions.Expression>,
System.Collections.Generic.IDictionary)' cannot be
inferred from the usage. Try specifying the type arguments
explicitly.
How can I fix this?Is it somehow connected with absense of field Password in AspNetUsers table and ApplicationUser Model?
you can't, because no password is stored and as you have stated too only the password hash gets stored in the db so the normal approach would be to retrieve the last password form the user and then hash it and compare it to the stored hash if they're equal then you can set the new provided password for the user the easier approach would be to use the user manager class and its UpdatePassword method
further reading :
https://msdn.microsoft.com/en-us/library/dn613290%28v=vs.108%29.aspx
I have the following view:
#model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
#{
ViewBag.Title = Resources.Edit;
}
<h2>#Resources.EditRole</h2>
#Html.ActionLink(Resources.ListRoles, "Index") | #Html.ActionLink(Resources.ManageUserRoles, "ManageUserRoles")
<hr />
<div class="row">
<div class="col-md-8">
<section id="editRoleForm">
#using (Html.BeginForm("Edit", "Role", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>#Resources.Role</h4>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(m => m.Name, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Name, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="#Resources.Save" class="btn btn-default" />
</div>
</div>
}
</section>
</div>
</div>
I also have the following two methods in my RoleController:
//
// GET: /Role/Edit/5
public ActionResult Edit(string Role)
{
var thisRole = context.Roles.Where(r => r.Name.Equals(Role, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
return View(thisRole);
}
//
// POST: /Role/Edit/5
[HttpPost]
public ActionResult Edit(FormCollection collection)
{
try
{
var thisRole = context.Roles.Where(r => r.Id.Equals(collection["Id"])).FirstOrDefault();
thisRole.Name = collection["Name"];
context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Originally, I was trying to use this method instead of the second one:
//
// POST: /Role/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(IdentityRole Name)
{
try
{
context.Entry(Name).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
But I never got it to work because the Name parameter was always null -which I still don't know why it happened, so if someone can explain it to me that'll be greatly appreciated.
I wrote then the other method since I saw the use of FormCollection in another example (to create roles) and it seems to work fine, at least it contains the information I need when I debug it. My issue is that although collection["id"] has the right Id for the Role I'm trying to edit, context.Roles is completely empty. This makes no sense to me given that when the first method is called (loading the View for the first time), this line
var thisRole = context.Roles.Where(r => r.Name.Equals(Role, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
returns the selected role (out of the several that exist and that I can see when I add to watch context.Roles). However, after the view is loaded, the textbox edited and the second method in the controller gets called, context.Roles has nothing in it. Why?
Ok you can use the already built in [Authorize(Roles="RoleType")] filter.
You then have your regular User model and Account controller so you can then authorize users. Once you have authorised them you can set them to a specific role.
E.g. user story: only admins can access action result x
[Authorize(User="Admin")]
Public ActionResult X(){
...
}
That way you simply assign user roles in the model creation.
E.g.
Public Class UserModel
{
int id {get;set;}
string name {get;set;}
string Role {get;set;}
.....
}
Now only users that have been authorised AND are of Role type "Admin" will be able to access that controller.
If you want to edit their role you can do a simple edit user action method
e.g.
[Post]
public actionresult edituser(int? id)
{
if (id == null)
{
return HttpNotFound();
}
using (var db = new UserContext())
{
UserModel editUser = db.UserModel.Find(id);
if (editUser == null)
{
return HttpNotFound();
}
db.User(editModel).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
}
RedirectToAction("Action", "Controller");
}
Now any user that is NOT of Role type "Admin" will not be able to access that screen. They will receive a 404 error.
This is actually two questions in one.
First question is about the following:
<div class="form-group">
#Html.LabelFor(model => model.xxx, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.xxx , new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.xxx, "", new { #class = "text-danger" })
</div>
</div>
I don't understand what model => model.xxx means, I know what it's doing but i don't know how to interpret the syntax.
the second question is, if I have - for example -
foreach (var item in Model)
how can I replace
#Html.EditorFor(model => model.xxx , new { htmlAttributes = new { #class = "form-control" } })
with
#Html.EditorFor(item.stringProperty , new { htmlAttributes = new { #class = "form-control" } })
when I try this, it gives me errors, is there an overloaded EditorFor helper that accepts this?
thank you!
One view can has 0 or 1 Model, which's sending from controller.
public class Person
{
public string Name {get;set;}
public int Age {get;set;}
}
public ViewResult Index()
{
Person p = new Person() { Name = "P1", Age = 100};
return View(p);//
}
if your View's name "Index" then you can use second way for View, which contain 2 parameters:
ViewName and model
return View("Index", model: p);
then in your View you can use the model, if it has been implemented that:
#model Person//and remember about namespace
#
{
...
}
#using(Html.BeginForm("ActionName", "controllerName", FormMethod.Post))
{
#Html.EditorFor(model => model.Name); // it create input, check in F12 in your browse - then you can exactly understand.
}
if you want create Editor for item you must use:
#Html.TextBox("YourName")
for example:
#using(Html.BeginForm("Action", "controller")
{
#Html.TextBox("YourName")
<input type="submit" value="ok"/>
}
and in your controllerController:
public ViewResult Action(string YourName)
{
//here you got value for string YourName
return View();
}
and helpfully answer's here:
ASP.NET MVC get textbox input value
Edit, answer about exactly problem (which containt in comment below question):
I have a list, and I want to display an input text box for each item in the list, but I want each text box to have text inside when its created, text from each item in the list (coming from the item's property)
#foreach(var item in Model)
#using(Html.BeginForm("MyMethod", "Controller"))
{
#Html.TextBox("item", item)
<input type="submit" value="ok" />
}
and in your controller add MyMethod:
[HttpPost]
public ViewResult MyMethod(string item)
{
...
}
or
[HttpPost]
public ViewResult MyMethod(int item) //if it's an int
{
...
}
and if you want to have a better security page please read about Html.AntiForgeryToken:
http://msdn.microsoft.com/en-us/library/dd470175(v=vs.118).aspx
#using(Html...())
{
#Html.AntiForgeryToken()
(...)
}
I see you already got the answer of your first question.
For the second one, i think
#Html.EditorFor(item => item.stringProperty , new { htmlAttributes = new { #class = "form-control" } })
will work fine
My Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(BlogCompModel blogmodel)
{
if (ModelState.IsValid)
{
...
}
}
My View:
#model BlogProject.Models.BlogCompModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
...
<div class="form-group">
#Html.LabelFor(model => model.BlogCompModel.posts, "Property", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.ListBoxFor(model => model.posts, new MultiSelectList(Model.posts, "post_ID", "postTitle"))
#Html.ValidationMessageFor(model => model.posts.posts)
</div>
</div>
}
Error message on post:
"The parameter conversion from type 'System.String' to type 'BlogProject.Models.Posts' failed because no type converter can convert between these types."} System.Exception {System.InvalidOperationException}
As you can see, I'm not sure how to translate the HTML Multiselect list from a collection of Post_IDs to an ICollection of posts.
Thanks!
You can add another property in your BlogCompModel Model, it'll wrap all selected post in it.
public class BlogCompModel
{
//
public string[] selectedPosts { get; set; }
}
Then in your view:
#Html.ListBoxFor(model => model.selectedPosts ,
new MultiSelectList(Model.posts, "post_ID", "postTitle"))
#Html.ValidationMessageFor(model => model.selectedPosts )
In my blog MVC app, I've a multiselect for Tags and here how I add those to Post in Create action.
Index.cshtml
#model MyBlog.Core.Post
#Html.ListBox("PostTags", (MultiSelectList)ViewBag.MultiSelectList, new { #class = "form-control" })
controller
public ActionResult CreatePost([Bind(Include = "Id,Title,ShortDescription,Description,Published,PostedOn,ModifiedOn,CategoryId")] Post post, int[] postTags)
{
if (postTags != null)
{
foreach (var t in postTags)
{
var tag = _dbTag.GetById(t);
post.Tags.Add(tag);
}
}
// save to database and other stuff
return View(post);
}