I'm building a simple application where a user can edit their profile including adding/deleting a brand image. This seems to be working fine and is updating the database no problem, however when refreshing the page and retrieving the user details via Membership.GetUser() the result includes the old results and not those from the updated database.
Here is my MembershipUser GetUser override:
public override MembershipUser GetUser(string query, bool userIsOnline)
{
if (string.IsNullOrEmpty(query))
return null;
var db = (AccountUser)null;
// ...get data from db
if (query.Contains("#")){
db = _repository.GetByQuery(x => x.Email == query).FirstOrDefault();
}
else
{
string firstName = query;
string lastName = null;
if (query.Contains(" "))
{
string[] names = query.Split(null);
firstName = names[0];
lastName = names[1];
}
// ...get data from db
db = _repository.GetByQuery(x => x.FirstName == firstName && x.LastName == lastName).FirstOrDefault();
}
if (db == null)
return null;
ToMembershipUser user = new ToMembershipUser(
"AccountUserMembershipProvider",
db.FirstName + " " + db.LastName,
db.ID,
db.Email,
"",
"",
true,
false,
TimeStamp.ConvertToDateTime(db.CreatedAt),
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue);
// Fill additional properties
user.ID = db.ID;
user.Email = db.Email;
user.FirstName = db.FirstName;
user.LastName = db.LastName;
user.Password = db.Password;
user.MediaID = db.MediaID;
user.Media = db.Media;
user.Identity = db.Identity;
user.CreatedAt = db.CreatedAt;
user.UpdatedAt = db.UpdatedAt;
return user;
}
Note I am using a custom MembershipProvider and MembershipUser. Here is where I am calling that method:
public ActionResult Edit()
{
ToMembershipUser toUser = Membership.GetUser(User.Identity.Name, true) as ToMembershipUser;
Now when I do a separate query just under this line of code straight to the database, not invoking MembershipUser, I get the updated result which in turn updates the MembershipUser result?!
It seems it may be caching the results? Anyway around this? I hope this is clear enough. Thanks
Edit:
It appears that when I set a breakpoint just after :
// ...get data from db
db = _repository.GetByQuery(x => x.FirstName == firstName && x.LastName == lastName).FirstOrDefault();
'db' retrieves the outdated results though surely this is talking to the database? If need be I'll update with my repository pattern
I managed to find a workaround though I'm not happy with this solution, so if anyone can improve upon this please post.
I decided to manually update the MembershipUser instance manually each time I update the image. My controller now looks like this:
private static ToMembershipUser MembershipUser { get; set; }
// GET: Dashboard/AccountUsers/Edit
public ActionResult Edit()
{
if(MembershipUser == null)
MembershipUser = Membership.GetUser(User.Identity.Name, true) as ToMembershipUser;
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
public JsonResult UploadMedia(IEnumerable<HttpPostedFileBase> files, int id)
{
var images = new MediaController().Upload(files);
if (images == null)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("File failed to upload.");
}
AccountUser accountUser = db.AccountUsers.Find(id);
db.Entry(accountUser).State = EntityState.Modified;
accountUser.UpdatedAt = TimeStamp.Now();
accountUser.MediaID = images[0];
db.SaveChanges();
MembershipUser.Media = accountUser.Media;
MembershipUser.MediaID = accountUser.MediaID;
return Json(new { result = images[0] });
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
public JsonResult DeleteMedia(int id)
{
bool delete = new MediaController().Delete(id, 1);
if (!delete)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("Error. Could not delete file.");
}
MembershipUser.Media = null;
MembershipUser.MediaID = null;
return Json("Success");
}
Related
I have the following code that needs to return a single value. However, I keep on getting null (the field Notifications_Id = 0) even though it clearly exists in the database.
var role = _context.AssignedTickets.FirstOrDefault(a => a.Notifications_Id == incidence.Notifications_Id);
I am using Net Core 5
Below is my code
public async Task<ActionResult> EditTicket(int? id)
{
{
if (id == null)
{
return StatusCode(400);
}
Incidence incidence = await _context.Incidences.FindAsync(id);
if (incidence == null)
{
return StatusCode(401);
}
return View(incidence);
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditTicket(Incidence incidence)
{
var role = _context.AssignedTickets.FirstOrDefault(a => a.Notifications_Id == incidence.Notifications_Id);
if (role == null)
{
return StatusCode(404);
}
role.Status = "C";
role.ClosedOn = DateTime.Now;
if (ModelState.IsValid)
{
DateTime Timeup = (DateTime)role.ClosedOn;
DateTime Timedown = (DateTime)role.CreatedOn;
long DiffTicks = (Timedown - Timeup).Ticks;
role.TurnAroundTime = Math.Abs(DiffTicks).ToString();
_context.Entry(incidence).State = EntityState.Modified;
_context.SaveChangesAsync();
return RedirectToAction("Dashboard", "Agent");
}
return View(incidence);
}
Please use var role = _context.AssignedTickets.FirstOrDefault(a => a.Notifications_Id == 29); to get the object, and then compare whether the attributes inside match the database.
I read your post and all comments carefully. What everyone said is very reasonable, and the code in the post is not problematic.
So I think the problem is likely to be a problem with the string connecting to the database, that is, a different database is used.
The problem is basically the Save changes method is not working (updating), the method should receive 3 parameters, item id, user id and the object which contains the updated information from the UI, however the code seems to be something bad because the saveChanges() method is not working.
This is my code:
[HttpPost]
[AllowAnonymous]
public JsonResult UpdatePersonalData(int ItemId, int UserId, CND_PersonalData Item)
{
try
{
if (ModelState.IsValid)
{
using (var context = new DexusEntities())
{
CND_PersonalData PersonalData = context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
if (PersonalData == null)
{
/// Display bad request
/// User does not exist and/or is not activated
List<RootObject> rootObj = new List<RootObject>();
rootObj.Add(new RootObject
{
msg = "User/Item not found in our DB",
code = "error_07"
});
HttpContext.Response.StatusCode = 404;
HttpContext.Response.TrySkipIisCustomErrors = true;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
else
{
PersonalData = Item;
context.SaveChanges();
context.ChangeTracker.DetectChanges();
List<RootObject> rootObj = new List<RootObject>();
rootObj.Add(new RootObject
{
msg = "Information stored/updated successfully",
code = "success_05"
});
HttpContext.Response.StatusCode = 200;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
}
else
{
List<RootObject> rootObj = new List<RootObject>();
JsonRes.Issue = "The model is not correct";
rootObj.Add(new RootObject
{
msg = "Model is not valid",
code = "error_03"
});
HttpContext.Response.StatusCode = 403;
HttpContext.Response.TrySkipIisCustomErrors = true;// Avoid issues in the HTTP methods
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
string err = ex.ToString();
List<RootObject> rootObj = new List<RootObject>();
JsonRes.Issue = err;
rootObj.Add(new RootObject
{
msg = "Conflict with method, see issue description.",
code = "error_08"
});
HttpContext.Response.StatusCode = 400;// Bad request
HttpContext.Response.TrySkipIisCustomErrors = true;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
What's wrong with my code?
Thanks in advance.
As I can see you are not adding an item into the DbSet and calling SaveChanges after:
When adding an item you should put it into DbSet
context.CND_PersonalData.Add(item);
context.SaveChanges();
when you want to update just call SaveChanges after you update loaded object
var PersonalData= context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
PersonalData.Name = item.Name;
PersonalData.Title = item.Title;
context.SaveChanges();
You can't just assign passed object to an entity you got from the DB, you need to change properties. If you do it as you did you didn't change values in the loaded object. So when you call SaveChanges nothing is changed. You need to change properties one by one.
If you don't want to do that then you can attach your item into the db by using Attach method on context.
context.Attach(item);
context.SaveChanges();
but you should be careful because if you load and track item with the same id as you are doing before checking if it is null:
CND_PersonalData PersonalData = context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
if (PersonalData == null)
{
then you will get an error during the save because the context is already tracking item with the same ID, so you can remove that check and just check if it exists:
if (context.CND_PersonalData.Any(d => d.Id == ItemId && d.UserId == UserId))
{
and then execute your code
I want to find the time at which Data is entered into my database. I'm using SQL Server as my database.
public class OtpchangeController : Controller
{
DateTime dbTime;
// GET: Otpchange
public ActionResult Generateotp()
{
return View();
}
[HttpPost]
public ActionResult Generateotp(tblPassword obj)
{
Random r = new Random();
using (PasswordGenerationEntities db = new PasswordGenerationEntities())
{
tblPassword newObj = (from c in db.tblPasswords
where c.Username == obj.Username
select c).First();
if(newObj != null)
{
int num = r.Next();
string newOtp = num.ToString();
newObj.Otp = newOtp;
db.SaveChanges();
dbTime = DateTime.Now;
Session["Username"] = newObj.Username.ToString();
return RedirectToAction("ChangePassword");
}
}
return View();
}
public ActionResult ChangePassword()
{
return View();
}
[HttpPost]
public ActionResult ChangePassword(tblPassword obj)
{
string name = #Session["Username"].ToString();
using (PasswordGenerationEntities db = new PasswordGenerationEntities())
{
tblPassword newObj = (from c in db.tblPasswords
where c.Otp == obj.Otp && c.Username == name
select c).First();
DateTime formTime = DateTime.Now;
TimeSpan result = dbTime.Subtract(formTime);
newObj.Password = obj.Password;
db.SaveChanges();
return RedirectToAction("Success");
}
//return View();
}
public ActionResult Success()
{
return View();
}
Here I want to find difference between the time when otp is added into database and the time when that otp is entered by the user.
But dbTime comes as 01/01/2001
But formTime is correct, also I want to find the difference between those time.
It seems the code you provided is not compiling or some parts are missing.
Anyway said I would suggest checking the msdn documentation about dbContext and its features here
You can delegate the database log to a console log or another more suitable provider(log4net or a simple custom log file). Those logs contain information about database execution times.
In your case you could do :
using (PasswordGenerationEntities db = new PasswordGenerationEntities())
{
db.Database.Log = Console.Write;
tblPassword newObj = (from c in db.tblPasswords
where c.Username == obj.Username
select c).First();
if(newObj != null)
{
int num = r.Next();
string newOtp = num.ToString();
newObj.Otp = newOtp;
db.SaveChanges();
dbTime = DateTime.Now;
Session["Username"] = newObj.Username.ToString();
return RedirectToAction("ChangePassword");
}
}
Check the console ouput.
Console Database info
I have a form where the user can edit their user account information and then save the new changes.
The problem I'm getting happens when I save the modified changes to the database.
On the line context.SaveChanges(), I get a DbUpdateConcurrencyException exception thrown. It says, "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."
I have no idea why.
Here's what I have done:
public ActionResult EditUserAccount()
{
UserAccountViewModel editUserAccountViewModel = new UserAccountViewModel();
editUserAccountViewModel.UserName = UserSession.GetValue(StateNameEnum.UserName, StateNameEnum.UserName.ToString()) as string;
int UserId = WebSecurity.GetUserId(editUserAccountViewModel.UserName);
var userInfo = context.db_user.First(x => x.UserId == UserId);
editUserAccountViewModel.Title = userInfo.Title;
editUserAccountViewModel.FirstName = userInfo.FirstName;
editUserAccountViewModel.LastName = userInfo.LastName;
editUserAccountViewModel.PhoneNumber = userInfo.PhoneNumber;
editUserAccountViewModel.AltPhoneNumber = userInfo.AltPhoneNumber;
editUserAccountViewModel.EmailAddress = userInfo.EmailAddress;
editUserAccountViewModel.UserAccountState = UserAccountViewModel.AccountState.EDIT;
return (PartialView("~/Views/Account/UserAccount.cshtml", editUserAccountViewModel));
}
[HttpPost]
public ActionResult EditUserAccount_Save(UserAccountViewModel editUserAccountViewModel)
{
try
{
if (ModelState.IsValid)
{
editUserAccountViewModel.UserName = UserSession.GetValue(StateNameEnum.UserName, StateNameEnum.UserName.ToString()) as string;
db_user user = new db_user();
user.Title = editUserAccountViewModel.Title;
user.FirstName = editUserAccountViewModel.FirstName;
user.LastName = editUserAccountViewModel.LastName;
user.PhoneNumber = editUserAccountViewModel.PhoneNumber;
user.AltPhoneNumber = editUserAccountViewModel.AltPhoneNumber;
user.EmailAddress = editUserAccountViewModel.EmailAddress;
user.LanguageId = context.languages.Where(t => t.Code == editUserAccountViewModel.Language).Select(t => t.Id).SingleOrDefault();
user.CreatedDate = DateTime.Now;
user.UserId = WebSecurity.GetUserId(editUserAccountViewModel.UserName);
context.Entry(user).State = EntityState.Modified;
context.SaveChanges();
JsonResult res = Json(new { Success = true, data = "", Message = "" });
return res;
}
else
{
JsonResult res2 = Json(new { Success = false, data = "", Message = "" });
return res2;
}
}
return null;
}
You are not creating an instance of context within the controller action, which would imply that it is at the class level. That means that context is shared with every other web request processed by that controller. This part of the error message Entities may have been modified or deleted since entities were loaded seems to confirm that hypothesis.
Instead, create an instance of context in your controller action.
Since you are editing an existing user in this action, you will first need to load the existing user into the context from the database, rather than instantiating a new one as you are now.
I strongly suspect that this change will resolve your issue.
UPDATE
Here's a code example. I don't know what your context class is called, so you might have to change that part. I assume that the user must already exist when this controller is called (based on the name of the method). I removed the try because you are not catching anything. If there is something useful you can do when an exception is thrown, go ahead and put that back in.
[HttpPost]
public ActionResult EditUserAccount_Save(UserAccountViewModel editUserAccountViewModel)
{
if (ModelState.IsValid)
{
using (MyContext context = new MyContext())
{
int userId = WebSecurity.GetUserId(editUserAccountViewModel.UserName);
db_user user = context.DbUsers.Where(u => u.Id == userId).Single();
editUserAccountViewModel.UserName = UserSession.GetValue(StateNameEnum.UserName, StateNameEnum.UserName.ToString()) as string;
user.Title = editUserAccountViewModel.Title;
user.FirstName = editUserAccountViewModel.FirstName;
user.LastName = editUserAccountViewModel.LastName;
user.PhoneNumber = editUserAccountViewModel.PhoneNumber;
user.AltPhoneNumber = editUserAccountViewModel.AltPhoneNumber;
user.EmailAddress = editUserAccountViewModel.EmailAddress;
user.LanguageId = context.languages.Where(t => t.Code == editUserAccountViewModel.Language).Select(t => t.Id).SingleOrDefault();
user.CreatedDate = DateTime.Now;
context.SaveChanges();
JsonResult res = Json(new { Success = true, data = "", Message = "" });
return res;
}
}
else
{
JsonResult res2 = Json(new { Success = false, data = "", Message = "" });
return res2;
}
}
I'm still very new to C# and would appreciate any help with my code.
I'm creating a user profile page and am getting the error "Nullable object must have a value" on "photo = (byte)user.Photo;" in the following code. I assume it's because I declared "photo = 0;" How do I add a value to it?
Update:
Here's the entire method
public static bool UserProfile(string username, out string userID, out string email, out byte photo)
{
using (MyDBContainer db = new MyDBContainer())
{
userID = "";
photo = 0;
email = "";
User user = (from u in db.Users
where u.UserID.Equals(username)
select u).FirstOrDefault();
if (user != null)
{
photo = (byte)user.Photo;
email = user.Email;
userID = user.UserID;
return true; // success!
}
else
{
return false;
}
}
}
I am assuming that you are getting error for this one...
if (user != null)
{
photo = (byte)user.Photo;
email = user.Email;
userID = user.UserID;
return true; // success!
}
else
{
return false;
}
If yes then just replace it with...
if (user != null)
{
photo = user.Photo== null ? null : (byte)user.Photo;
email = user.Email;
userID = user.UserID;
return true; // success!
}
else
{
return false;
}