i have been trying to implement custom login where i'll be updating the password but db.savechanges isn't working with my code - asp.net-mvc

public ActionResult ChangePassword(ChangePassword model)
{
if (ModelState.IsValid)
{
UserDetail ud = db.UserDetails.FirstOrDefault(s => s.UserName == User.Identity.Name);
try
{
if (ud.Password == model.OldPassword)
{
ud.Password = model.NewPassword;
TryUpdateModel(ud);
**db.SaveChanges();**
return RedirectToAction("ChangePasswordSuccess");
}
else
{
ViewBag.ErrorMsgForPassword = "old password is not correct";
}
}
catch
{
return View();
}
}

while password change the complex types were not loaded so while updating he password db.savechanges() didn't work so if you load the complex types(addresses in this case) the problem is solved

Related

The bool value always is always taken as false but its true in database? MVC

I have defined user(admin) type as 'bit' data type in my database. So if value is true it should go to a specific page otherwise it should return the same view. But whenever I pass object (adminObj) with different values the if statement only returns 'false' from database. Can somebody help where is the problem ?
here is my logic
[HttpPost]
public ActionResult Login(tbl_Admin adminObj)
{
studentDBEntities db = new studentDBEntities();
var adminvar = db.tbl_Admin.Where(x => x.Email == adminObj.Email && x.Password == adminObj.Password).FirstOrDefault();
var type=adminObj.Type;
if (adminvar != null)
{
/*var isGlobal=*/
if (adminObj.Type == true)
{
return RedirectToAction("ListAdmin");
}
else
{
return View();
}
}
else
{
return View();
}
}
Values in Database-Table:
When Type=1
Alright, I found the logical error here. I was calling the login object instead of the object which was actually storing the fetched data. So I should call var type=adminvar.Type; instead of var type=adminObj.Type;
So The Corrected logic will be
[HttpPost]
public ActionResult Login(tbl_Admin adminObj)
{
studentDBEntities db = new studentDBEntities();
var adminvar = db.tbl_Admin.Where(x => x.Email == adminObj.Email && x.Password == adminObj.Password).FirstOrDefault();
if (adminvar != null)
{
if (adminvar.Type== true)
{
return RedirectToAction("ListAdmin");
}
else
{
return View();
}
}
else
{
return View();
}
}

what should a method return from service layer

I am just wondering about the way to validate my viewmodel.
A user can own only one team, so I have to check it somehow if he hasn't got one.
public ActionResult AddTeam(TeamCreatingViewModel teamToAdd)
{
if (ModelState.IsValid)
{
//check if the user has got a team
if (!TeamService.checkIfUserHasCreatedTeam(User.Identity.GetUserId()))
{
//if not then allow him to create one
if (!TeamService.addTeam(teamToAdd, User.Identity.GetUserId()))
{
ViewBag.Info = "Success";
return View("Info");
}
else
{
ViewBag.Info = "It was impossible to create a new team";
return View("Error");
}
}
else
{
ViewBag.info = "You have a team!";
return View("Error");
}
}
else
{
return View("TeamCreatingForm", teamToAdd);
}
}
Or would the solution below be better ?
public ActionResult AddTeam(TeamCreatingViewModel teamToAdd)
{
if (ModelState.IsValid)
{
if (!TeamService.addTeam(teamToAdd, User.Identity.GetUserId())) //<--- now it is checking and adding (if allowed)
{
ViewBag.Info = "Success";
return View("Info");
}
else
{
ViewBag.Info = "It was impossible to create a new team";
return View("Error");
}
}
else
{
return View("TeamCreatingForm", teamToAdd);
}
}
How can I report (from service layer) if an error has occured (and what kind of )? In the second case, users won’t know anything about what was done wrong.
And in the first case I have to get an entity object 2 times, what seems to be useless.
You can report errors from business layer by throw out param, for example
public bool AddItem(string name, out List<string> errors){...}// or just string with error

How to edit/update records using "TryUpdateModel" with "User.Identity.GetUserId()" in mvc.net?

This following code works fine
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int? id, string[] selectedCourses)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var instructorToUpdate = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses)
.Where(i => i.ID == id)
.Single();
if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
{
try
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
{
instructorToUpdate.OfficeAssignment = null;
}
UpdateInstructorCourses(selectedCourses, instructorToUpdate);
db.SaveChanges();
return RedirectToAction("Index");
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
PopulateAssignedCourseData(instructorToUpdate);
return View(instructorToUpdate);
}
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.Courses.Select(c => c.CourseID));
foreach (var course in db.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}
}
}
But I don't want to get id from view and I am using string id = User.Identity.GetUserId(); but only my checkboxes are getting updated and not the other database.
I tried db.Entry(abc).State = EntityState.Modified; but it gives an error. It says, context is already in use. How to update both tables?

Making Sessions in MVC 6 Controller(with views, using Entity Framework)

I'm attempting to create a session in my UserAccountsController
using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Data.Entity;
using POPPELWebsite.Models;
namespace POPPELWebsite.Controllers
{
public class UserAccountController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Register()
{
return View();
}
[HttpPost]
public ActionResult Register(UserAccount account)
{
if (ModelState.IsValid)
{
using (OurDbContext db = new OurDbContext())
{
db.userAccount.Add(account);
db.SaveChanges();
}
ModelState.Clear();
ViewBag.Message = account.FirstName + " " + account.LastName + " successfully registered.";
}
return View();
}
//Login
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(UserAccount user)
{
using (OurDbContext db = new OurDbContext())
{
var usr = db.userAccount.Single(u => u.Email == user.Email && u.Password == user.Password);
if (usr != null)
{
Session["UserID"] = usr.UserID.ToString;
}
}
}
}
}
I get an error saying
the name Session does not exist in the current context.
I need to do this part to complete a registration and login tutorial for mvc
The Session property does not exist in the Controller class in MVC 6, instead use HttpContext.Session to access the session property.
Ex:
// get values
string strValue = HttpContext.Session.GetString("StringKey");
int intValue = HttpContext.Session.GetInt32("IntKey");
byte[] byteArrayValue = HttpContext.Session.Get("ByteArrayKey");
// set values
HttpContext.Session.Set("ByteArrayKey", byteArrayValue);
HttpContext.Session.SetInt32("IntKey", intValue);
HttpContext.Session.SetString("StringKey", strValue);
Try this.
public ActionResult Login(User users)
{
if (ModelState.IsValid)
{
using (DataContext db = new DataContext())
{
var obj = db.Users.Where(u => u.Username.Equals(users.Username) && u.Password.Equals(users.Password)).FirstOrDefault();
if(obj !=null)
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
context.Session["UserId"] = obj.UserId.ToString();
context.Session["Username"] = obj.Username.ToString();
return RedirectToAction("Dashboard");
}
}
}
return View(users);
}

Explicit password and email validation in Microsoft.AspNet.Identity, why needed?

I am big fan of Adam Freeman's books. At his Pro Asp.net mvc 5 platform, in chapter 13, page 325, the following code confused me. Does anyone have the explanation why he used the email and password validation explicitly?
The call this.UserManager.UpdateAsync(user) should return a result with same errors generated by this.UserManager.UserValidator.ValidateAsync(user) and this.UserManager.PasswordValidator.ValidateAsync(password). Is he not doing the same thing twice? Or there is a special purpose?
[HttpPost]
public async Task<ActionResult> Edit(string id, string email, string password)
{
AppUser user = await this.UserManager.FindByIdAsync(id);
if (user != null)
{
user.Email = email;
IdentityResult validEmail = await this.UserManager.UserValidator.ValidateAsync(user);
if (!validEmail.Succeeded)
{
this.AddErrorsFromResult(validEmail);
}
IdentityResult validPass = null;
if (password != string.Empty)
{
validPass = await this.UserManager.PasswordValidator.ValidateAsync(password);
if (validPass.Succeeded)
{
user.PasswordHash = this.UserManager.PasswordHasher.HashPassword(password);
}
else
{
this.AddErrorsFromResult(validPass);
}
}
if ((validEmail.Succeeded && validPass == null)
|| (validEmail.Succeeded && password != string.Empty && validPass.Succeeded))
{
IdentityResult result = await this.UserManager.UpdateAsync(user);
if (result.Succeeded)
{
return this.RedirectToAction("Index");
}
this.AddErrorsFromResult(result);
}
}
else
{
ModelState.AddModelError(string.Empty, "User not found");
}
return this.View(user);
}
private AppUserManager UserManager
{
get
{
return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
}
}
private void AddErrorsFromResult(IdentityResult result)
{
foreach (string error in result.Errors)
{
ModelState.AddModelError(string.Empty, error);
}
}
in source code of identity UserManager class UpdateAsync method is like this:
public virtual async Task<IdentityResult> UpdateAsync(TUser user)
{
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException("user");
}
var result = await UserValidator.ValidateAsync(user).ConfigureAwait(false);
if (!result.Succeeded)
{
return result;
}
await Store.UpdateAsync(user).ConfigureAwait(false);
return IdentityResult.Success;
}
that calls UserValidator.ValidateAsync(user) method for validating that username is not illegal or user not registered before with a different Owner Id and does not care for validating Email address or password string. if you want to validate passwords and do your custom checks you must create custom validators .
you can find Default UserValidator source code here

Resources