I have ASP.NET MVC 4 appliation using EF 4.3 with migrations. I use a WebGrid Helper to display details for system users:
@grid.GetHtml(
headerStyle: "gridHeader",
footerStyle: "gridFooter",
firstText: "<< First",
previousText: "< Previous",
nextText: "Next >",
lastText: "Last >>",
alternatingRowStyle: "gridAlternativeRow",
columns: new[] {
grid.Column("Login", header: "User Login", canSort: true),
grid.Column("FullName", header: "User Name", canSort: true),
grid.Column("Email", header: "User Email", canSort: true),
grid.Column("Category", header: "User Category", canSort: true),
grid.Column(
"",
header: "",
format: @<text>
@Html.ActionLink("Edit", "Edit", new { id=item.Id} )
</text>
)
})
As you can see Edit action method is responsible for editing user details. This is how it passes the View Model to the view:
public ActionResult Edit(int Id)
{
User user = repo.GetUser(Id);
RegisterModel rm = new RegisterModel();
rm.Id = user.Id;
rm.Name = user.FullName;
rm.UserName = user.Login;
rm.Email = user.Email;
rm.UserCategory = user.Category;
rm.Categories = new List<SelectListItem>();
List<Category> categories = repo.GetAllCategories();
foreach (var item in categories)
{
SelectListItem sli = new SelectListItem();
sli.Value = null;
sli.Text = item.Title;
if (user.Category == item.Title) sli.Selected = true;
rm.Categories.Add(sli);
}
return View(rm);
}
And this is how its saves the details:
[HttpPost]
public ActionResult Edit(RegisterModel rm, string NewPassword, string OldLogin)
{
if (NewPassword != "")
{
var token = WebSecurity.GeneratePasswordResetToken(OldLogin);
WebSecurity.ResetPassword(token, NewPassword);
}
User user = new User();
user.Id = Convert.ToInt32(rm.Id);
user.FullName = rm.Name;
user.Email = rm.Email;
user.Category = rm.UserCategory;
user.Login = rm.UserName;
string result = repo.UpdateUserDetails(user);
return RedirectToAction("Index");
}
Then it redirects to Index anction method which sources list of users and passes it back to the View with WebGrid Helper.
Every single time I hit the repository I source the most recent values for users from DbContext object:
public List<User> GetAllUsersWithoutAdmin()
{
return context.Users.Where(x => x.Id != 1).OrderBy(x => x.FullName).ToList();
}
public User GetUser(int userId)
{
return context.Users.FirstOrDefault(x => x.Id == userId);
}
public string UpdateUserDetails(User user)
{
string info;
try
{
User uUser = context.Users.FirstOrDefault(x => x.Id == user.Id);
uUser.Category = user.Category;
uUser.Email = user.Email;
uUser.FullName = user.FullName;
uUser.Login = user.Login;
context.SaveChanges();
info = "success";
}
catch (Exception err)
{
info = err.Message;
}
return info;
}
Also I use UoW pattern to solve the problem of using different repositories in the same controller:
public interface IUnitOfWork
{
int SaveChanges();
}
Each repository then implements this interface:
private ActivityLogContext context;
public UserRepository(IUnitOfWork _context)
{
context = _context as ActivityLogContext;
}
And shares it in the same context in the scope of the thread which is implemented in the Ninject Controller Factory by AddBindings() method:
private void AddBindings()
{
ninjectKernel.Bind<IActivityRepository>().To<ActivityRepository>();
ninjectKernel.Bind<IUserRepository>().To<UserRepository>();
ninjectKernel.Bind<ICategoryRepository>().To<CategoryRepository>();
ninjectKernel.Bind<IUnitOfWork>().To<ActivityLogContext>().InThreadScope();
}
A PROBLEM: For some strange reason, once every so often, when user object is being edited, context object presents wrong values for the user properties. It is happening on the level of EF somewhere between the DbContext and actual data. Especially, that data in SQL server is always right. It looks like EF is caching previous values for the properties and takes those instead of sourcing them from database. I have not observed when this behaviour exactly occurs, but it happens rather often - every second or third time when object is edited. Sometimes it happens couple of times in the row.
I have used the same setup in previous application and everything was fine. The only difference this time is that I'm using WebGrid Helper, and only pages with WebGrid Helper seem to cause this problem in my application???