I am trying to update user details.
Here is my code.
My Model-
public class ApplicationUser : IdentityUser
{
public string Name { get; set; }
public string MobileNumber { get; set; }
public string Email { get; set; }
}
The Controller-
[HttpPost]
public ActionResult UpdateUser(ApplicationUser UserProfile)
{
if (ModelState.IsValid)
{
var result = UserManager.Update(UserProfile);
if (result.Succeeded)
return View(UserProfile);
else
{
return View(UserProfile);
}
}
return View(UserProfile);
}
"result.Error.strings" gets the value
Name suresh already taken
Based upon the the error message, i'm guessing your Database already has the user with name Suresh
Try another name if the error still exists update your question and my be you can get more help.
The other way you could update an user could be first find the user then update the required fields then update(save) user.
I had the same problem. figured out that when one does not set the ID of the user that needs to be updated, the EF context undercover treats the user object as the new entity.
fixing the error with the ID, I've got a new error, so to help anyone struggling (and to scip a couple of steps) - I pointing to an answer that explains it:
asp.net identity 2.0 update user
Related
My current employer is developing a mobile app using Xamarin.Forms and Asp.net mvc on the backend. I suggested to use realm in the mobile app. My manager want to see a POC(Proof of concept) app using realm with backlink feature before allowing it to be used in the app. I am working on the POC on GitHub . The documentation is very limiting and the GitHub repo of realm-dotnet don’t have good sample.
I completed the project. But unable to implement backlink. The sample app I have developed allow user to create assignees(employees) in the first page. The user can delete or edit the employees using context menu. When the user clicks on the employee name the app navigates to the ToDoListPage of that particular employee. Here the user can create ToDoItems. On this ToDoList page I want to show the ToDoItems that where assigned to that employee only.
The models were as follows:
public class Assignee : RealmObject
{
public Assignee()
{
ToDoItems = Enumerable.Empty<ToDoItem>().AsQueryable();
}
[PrimaryKey]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Name { get; set; }
public string Role { get; set; }
[Backlink(nameof(ToDoItem.Employee))]
public IQueryable<ToDoItem> ToDoItems { get; }
}
public class ToDoItem : RealmObject
{
[PrimaryKey]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Name { get; set; }
public string Description { get; set; }
public bool Done { get; set; }
public Assignee Employee { get; set; }
}
I am adding employee to each ToDo Item:
Item.Employee = Employee;
_realm.Add(Item);
Now I want to access the ToDoItems for the Employee:
Items = _realm.All<Assignee>().Where(x => x.Id == EmployeeId).FirstOrDefault().ToDoItems;
But this does not work. I will be grateful if someone can help me out by preferably writing code in my sample app or write the correct code in the reply.
Thank you
Firstly, Realm .NET doesn't currently support traversing properties (x.Employee.Id). Due to this, when I start the app and try to go to the ToDoListPage, the app crashes with the exception:
The left-hand side of the Equal operator must be a direct access to a persisted property in Realm
Realm supports object comparison, so we can fix this like so:
var employee = _realm.Find<Assignee>(EmployeeId);
Items = _realm.All<ToDoItem>().Where(x => x.Employee == employee);
Secondly, everything seemed fine in your code, so I dug a bit deeper and saw why it isn't working. The issue is that when we try to get all items with the code above, the EmployeeId parameter is null. Since the EmployeeId is being populated after the load logic has been triggered, we don't need to load the data in the ctor. So you can remove this code.
Finally, since you won't be loading the data in the ctor, and instead in the SetValues method, the UI needs to know, when the data has been updated, what exactly to redraw. Thus, you need to mark the collection to be Reactive too:
[Reactive]
public IEnumerable<ToDoItem> Items { get; set; }
Then, you need to change the SetValues method to use object comparison, instead of traversing:
async Task SetValues()
{
Employee = _realm.Find<Assignee>(EmployeeId);
Title = Employee.Name;
Items = _realm.All<ToDoItem>().Where(x => x.Employee == Employee);
}
To sum up - you don't need to try and load the data in the ctor, since you don't know when the EmployeeId will be set. You are already tracking when the property will change and inside the SetValues command you simply need to change the expression predicate.
I have the following code :
public Exam CreateExam(string name, List<Question> questions, DateTime timeNow)
{
User user = GetUserByName(name);
Exam exam = new Exam()
{
Questions = questions,
StartDate = timeNow,
User = user
};
Context.Exams.Add(exam);
Context.SaveChanges();
return exam;
}
Exam :
public class Exam
{
public int Id { get; set; }
public DateTime StartDate { get; set; }
public User User { get; set; }
public virtual List<Question> Questions { get; set; }
}
And user has the basic user infos.
My problem is that when I create an exam for the user, the save change also add a new user to the database, with only the ID being different. How do I prevent that and make it understand that I want to link it to the existing user ?
Thank you !
Edit: GetUserByName() :
Context.Database.SqlQuery<User>("Select * from Users where name = #name", new SqlParameter("name", name)).FirstOrDefault();
When you use SqlQuery to fetch user, he will not be tracked by Entity Framework, because you can write arbitrary query and map result to User class. So EF consider, that he is new one, when you reference to him. To fix this problem, you should manually attach his to context:
User user = GetUserByName(name);
Context.Users.Attach(user);
Based Slava Utesinov answer Entity Framework's change tracker does not track entity changes when get from raw query such as:
Context.Database.SqlQuery<User>("Select * from Users where name = #name", new SqlParameter("name", name)).FirstOrDefault();
Therefore when you call SaveChanges() method, Entity Framework change tracker detect user entity state as Added (new entity)
1.you can use DbSet.SqlQuery instead of Database.SqlQuery because DbSet.SqlQuery will tracked by the context:
Context.Users.SqlQuery("Select * from Users where name = #name", new SqlParameter("name", name)).FirstOrDefault();
or
2.you can attach entity to current context dbset as unchanged state
I am new to Razor Pages, and am trying to understand how I can set a required field in a page's OnPostAsync method. Specifically, I have a bound object which needs to include the current user's ID (from ASP.NET Identity). I can set this value in OnPostAsync, but the ModelState still shows as invalid. Checking the returned errors, it seems that it is not taking the updated value into consideration
Here's my current OnPostAsync method:
public async Task<IActionResult> OnPostAsync()
{
Upload.Created = DateTime.Now;
Upload.UploaderID = _userManager.GetUserId(User);
if (!ModelState.IsValid)
{
return Page();
}
_context.Uploads.Add(Upload);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
And here's a snippet from the Upload model:
public class Upload
{
...
[Required]
public String UploaderID { get; set; }
[ForeignKey("UploaderID")]
public ApplicationUser Uploader { get; set; }
...
}
Apologies if there is something obvious I am missing here, as I say I am new to Razor Pages/Entity Framework and my Google-fu has failed me.
I solved the problem by adding the following line after setting the UploaderID but before the ModelState check:
ModelState.Remove("Upload.UploaderID");
This stops the UploaderID from being checked for errors with the rest of the ModelState.
i have some question regarding to edit/delete operation via asp.net mvc or web applications in general.
Lets say i have the following url to delete or edit records : app/delete/5, app/edit/5 to edit or delete record with id 5.
When calling the link, a confirmation page is loaded via HTTP GET and the edit/delete operation itself is done via HTTP POST.
Once user knows the link, how can i prevent him from calling any other app/delete or app/edit for records he does not own or is not permitted to edit/delete? Example: app/delete/7312
What do i have to put in my controller action that the user can only fetch the confirmation page via GET for the records he is permitted to execute an edit/delete?
Best regards
marc
Okay at first I posted a simpler answer but I didn't understand the question. You are going to need two things. A way to know who created what in the system, and then some business logic in the delete action checking if the current user is equal to the user who created it. I would suggest this inheritable class that i use to track ownership of an object:
public class BaseEntity
{
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = false)]
[Display(Name = "Date Created")]
[DataType(DataType.Date)]
public DateTime? DateCreated { get; set; }
public string UserCreated { get; set; }
[Display(Name = "Date Modified")]
[DataType(DataType.Date)]
public DateTime? DateModified { get; set; }
public string UserModified { get; set; }
}
Then in your database context class, you can overwrite save changes to automatically track these things whenever a user in the system saves something t o populate those fields. This is handy because you don't have to go into Create, Edit, etc. and manually link this up.
public override int SaveChanges()
{
var entities = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified));
var currentUsername = HttpContext.Current != null && HttpContext.Current.User != null
? Users.Find(HttpContext.Current.User.Identity.GetUserId()).Name
: "Anonymous";
foreach (var entity in entities)
{
if (entity.State == EntityState.Added)
{
((BaseEntity)entity.Entity).DateCreated = DateTime.Now;
((BaseEntity)entity.Entity).UserCreated = currentUsername;
}
((BaseEntity)entity.Entity).DateModified = DateTime.Now;
((BaseEntity)entity.Entity).UserModified = currentUsername;
}
return base.SaveChanges();
}
Then finally, to actually achieve your functionality, you can in your controller's delete action only let the delete go through if Users.Find(HttpContext.Current.User.Identity.GetUserID()).name is equal to the name of whoever created the model.
I know this is a lot, if you have questions please comment I'll check in.
I would like to extend Application User. Here's an example:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
I tried this but it seems like when I login if any of these properties is set to a null in the database then when the /Token call is made it returns with an error.
Can someone tell me. Do I need to make a change to the way these properties are set here or in another place?
If i understand your question correctly, a simple solution to your problem could be to create a nullable type. Can you please share what you would like to do? Create a custom identity provider, for example?