Html.EditFor passing in a new value MVC - asp.net-mvc

Ive been looking around trying to figure this out but have had no luck.
What I want to do is pass the UserId of the person that is logged in, which I already have in UserID from my model. I have the code below and need to pass in UserID instead of last_update_by_IN.
<div class="form-group">
#Html.LabelFor(model => model.last_update_by_IN, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.last_update_by_IN)
#Html.ValidationMessageFor(model => model.last_update_by_IN)
</div>
</div>
I tried
<div class="form-group">
#Html.LabelFor(model => model.last_update_by_IN, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserID)
#Html.ValidationMessageFor(model => model.last_update_by_IN)
</div>
</div>
but that was displaying the correct UserID but passing 0 to the database. Let me know if I need to clarify things more. Thanks
here is the post in my controller, forgot to add this sorry
public ActionResult Edit([Bind(Include="column names here")] User_Accounts user_accounts)
{
if (ModelState.IsValid)
{
db.Entry(user_accounts).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.user_type_id_IN = new SelectList(db.User_Type, "userId", "userType", user_accounts.user_type_id_IN);
ViewBag.userId = new SelectList(db.Userinfo, "userId", "pinId", user_accounts.user_id_IN);
return View("Edit", user_accounts);
}

Related

Edit user removes password - ASP.NET MVC

I am trying to edit the data for one of my users. However, whenever I edit something, the passwords which are hidden, are also being changed and apparently set to null, which render the user unable to log in next time he wants to login. I know that I might have been able to solve the issue by using ViewModels, but im trying to do it without.
Model
public class User : IdentityUser
{
[Display(Name = "First name")]
public String FirstName { get; set; }
[Display(Name = "Last name")]
public string LastName { get; set; }
public string Email{ get; set; }
}
Please notice that the User-class extends from IdentityUser which holds password variables.
Edit in Controller
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "FirstName,LastName,Email,PhoneNumber")] User user)
{
if (ModelState.IsValid)
{
db.Entry(user).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
View for Edit
<div class="form-horizontal">
<h4>User</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.FirstName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.LastName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.LastName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LastName, "", 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>
<div class="form-group">
#Html.LabelFor(model => model.PhoneNumber, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PhoneNumber, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PhoneNumber, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
It is my understand that the Bind-parameter in the Edit-method either whitelist or blacklist the variables for editing. So for that reason i removed all of the values that shouldnt be edited by the user in Bind.
There are a couple of problems here. First, don't present these fields to the user in the first place. I can't imagine a reason why a user should be able to edit their "locked out" status, or their hashed password. Only include in the UI the fields which the user should actually be modifying. Hell, even this has horrible idea written all over it:
#Html.HiddenFor(model => model.Id)
You're not only allowing the user to edit everything about their user record, but you're also allowing them to specify another user record to edit. So any user in the system can completely edit any other user in the system.
Hopefully you see how this is a bad thing :)
Now, you can (and often must) include the identifier in a hidden field. The above problem is mainly bad because of what else you're doing:
db.Entry(user).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
You are completely and implicitly trusting whatever the user sends you to be a whole, correct, and complete record for the database. And replacing whatever existing record is there with whatever the user sends you. That's... not good.
This approach can work for some models, but certainly not sensitive ones like user security data.
Instead, fetch the existing record and only edit the necessary fields. Something like this:
var existingUser = db.Users.Single(u => u.Id == currentUserId);
existingUser.FirstName = user.FirstName;
existingUser.LastName = user.LastName;
// etc.
db.SaveChanges();
Notice that I used an otherwise undefined variable called currentUserId. Do not use model.Id, because again that's allowing the user to specify which other user they want to edit. Determing the current user ID by their current logged in session, not by what they send in the form. However you currently identify your users. (User.Identity?)
In short...
Only let the user see/edit what they're allowed to
Validate in the save action that the user is allowed to edit that data (never assume that they must be allowed to simply because they previously opened the page)
Only update the values meant to be updated in that operation, don't just wholesale replace an entire record of sensitive data

Unable to Call a method if i mentioned its attribute as HttpPost

I have a signin page which users can use to signin,i defined its method in controller as HttpPost,when i try to access it from browser,it shows no file found,if i remove the HttpPost attribute it hits the controller and return the view.Eventhough it pass the values in the form to controller if i didnt mentioned its type as HttpPost .Here my code of Login/SignIn.cshtml:
#model BOL.Player_Access
#using (Html.BeginForm("SignIn","Login",FormMethod.Post)){
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Sign In</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.PlayerEmail, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PlayerEmail, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PlayerEmail, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Password, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Password, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Password, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="SignIn" class="btn btn-default" />
</div>
</div>
</div>
And my LoginController Code is here
[AllowAnonymous] //This filter removes authorize filter for this controller alone and allow anonyomous request
public class LoginController : Controller
{
// GET: Login
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult SignIn(Player_Access plyr_obj)
{
return View();
}
}
You need code for both GET and POST.
You need a GET action to show the form that will be POST'ed
public ActionResult SignIn()
{
return View();
}
This will show the SignIn view.
Then you need a POST action to take the values from the form and send them to the controller.
[HttpPost]
public ActionResult SignIn(Player_Access plyr_obj)
{
//do some work to authenticate the user
return View();
}

How get List<~> fron View to Controller MVC [duplicate]

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 6 years ago.
I have three related tables
Tables
In the table "SelectedMaterial" need to enter the values in the column "CountMaterial" (initially there null)
Values
For this in controller I have POST and GET methods
public ActionResult EditCountOfMaterial(int id)
{
var selectedmaterial = db.SelectedMaterials.Where(m => m.CardId == id).ToList();
return View(selectedmaterial);
}
[HttpPost]
public ActionResult EditCountOfMaterial(List<SelectedMaterial> material)
{
//material = db.SelectedMaterials.Where(m => m.CardId == 3).ToList();
for (int i = 0; i < material.Count; i++)
{
//material[i] = db.SelectedMaterials.Where(m => m.CardId == 3).First();
db.Entry(material[i]).State = EntityState.Modified;
db.SaveChanges();
}
return RedirectToAction("Index");
}
I also have a view
#model IEnumerable<AccountingPlusProject.Models.SelectedMaterial>
#{
ViewBag.Title = "EditCountOfMaterial";
}
<h2>EditCountOfMaterial</h2>
#using (Html.BeginForm())
{
foreach (var item in Model)
{
#item.ReferenceMaterial.NameMaterial
<div class="form-group">
#Html.LabelFor(model => item.CountMaterial, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => item.CountMaterial, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => item.CountMaterial, "", new { #class = "text-danger" })
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
But from the view comes null values. How to pass list from View with a value?
Something like Below. The Posted back values have to be in array form.
#using (Html.BeginForm())
{
foreach (var item in Model)
{
var count= 0;
#item.ReferenceMaterial.NameMaterial
<div class="form-group">
#Html.LabelFor(model => item.CountMaterial, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => item.CountMaterial, new { htmlAttributes = new { #class = "form-control", #name="SelectedMaterial[" + count.ToString() + "].CountMaterial"} })
#Html.ValidationMessageFor(model => item.CountMaterial, "", new { #class = "text-danger" })
</div>
</div>
count+=1;
}
}

Use same partial to add form to Create and Edit actions

When you create a new scaffolded item on VS it creates the views for Create and Edit actions that are almost identical, with the exception of the Edit view having an #Html.HiddenFor for your primary key.
Example of Edit view:
#model MyApp.Models.Destaque
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(m => m.IdDestaque)
<div class="form-group">
#Html.LabelFor(model => model.Mensagem, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Mensagem, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Mensagem, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CaminhoImagem, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CaminhoImagem, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CaminhoImagem, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UrlLink, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UrlLink, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.UrlLink, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Salvar" class="btn btn-primary" />
</div>
</div>
</div>
}
If I place all content from the BeginForm (including the #using (...) and keep the #Html.HiddenFor(m => m.IdDestaque) in a _Form partial, it doesn't allow me to create new rows.
If I remove the #Html.HiddenFor from the _Form partial, the Edit action does not work (ModelState is invalid).
So what is the right way to do this and keep the DRY principles? Removing the PK from the ModelState validation in my Edit action seems an "uggly" workaround.
You should render the id of your model inside the view and use another overload for Html.BeginForm as follows:
#using (Html.BeginForm("Edit", "Controller", FormMethod.Post, new{attr1 = value1, attr2 = value2}))
{
#Html.HiddenFor(x => x.Id)
...
}
You always make a post to the EditAction. In you controller you will then only need one POST action for Edit and two get actions one Create and other Edit.
public ActionResult Create()
{
return View("Edit"); //return the edit view
}
public ActionResult Edit(int id)
{
var entity = manager.FetchById(id);
if (entity == null)
return HttpNotFound();
//convert your entity to model (optional, but recommended)
var model = Mapper.Map<ViewModel>(entity);
//return your edit view with your model
return View(model);
}
[HttpPost]
public ActionResult Edit(ViewModel model)
{
if (ModelState.IsValid)
{
//work with your model
return RedirectToAction("Index", "Controller");
}
//at this point there is an error, so your must return your view
return View(model);
}
Hope this helps!

Why DefaultModelBinder doesn't bind route value ID from URL

ASP.NET MVC
In short:
I have a get action and a post action
when I type in browser localhost:port/Employee/Edit/1 I call get action, so in URL I have this whole url string. When I press submit button, in post action defaultmodelbinder doesnt bind id from URL!!!! I HAVE TO ADD HIDDEN FIELD for id. But why? I also have delete action (post), that gets id too, and I dont need to add hidden field for id. why?
More specifically:
I have the model:
public class EmployeeViewModel
{
public Int32 EmployeeId { get; set; }
public String Name { get; set; }
public String Phone { get; set; }
public String Email { get; set; }
public String Other { get; set; }
}
And 2 actions
public ActionResult Edit(int id)
{
try
{
EmployeeViewModel model;
using (var dbSession = NHibernateHelper.OpenSession())
{
var employee = dbSession.Query<Employee>().First(e => e.EmployeeId == id && e.ExpireDate==null);
model = new EmployeeViewModel(employee);
}
return View(model);
}
catch
{
return View("Error");
}
}
[HttpPost]
public ActionResult Edit(EmployeeViewModel model)
{
try
{
using (var dbSession=NHibernateHelper.OpenSession())
using (var transaction=dbSession.BeginTransaction())
{
var employee = model.ToEmployee();
dbSession.Merge(employee);
transaction.Commit();
}
return RedirectToAction("Index");
}
catch
{
return View("Error");
}
}
And 1 View (HERE I HAVE TO WRITE THIS LINE #Html.HiddenFor(model => model.EmployeeId) )
#using (Html.BeginForm()){
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.HiddenFor(model => model.EmployeeId)
#Html.LabelFor(model => model.Name, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.Name, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Phone, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Phone, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Phone, "", 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>
<div class="form-group">
#Html.LabelFor(model => model.Other, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Other, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Other, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Сохранить" class="btn btn-default" />
</div>
</div>
</div>}
Because the parameter in the method is named id and the property in
your model is named EmployeeId They are not the same. And if you
change the model property to Id it will be bound
Thanks, Stephen Muecke

Resources