I tried this, but the user always ends up being null:
ApplicationDbContext db = new Models.ApplicationDbContext();
var user = db.Users.Find(Context.User.Identity.Name);
if (user == null)
{
caller.displayMessage("Error: User does not exist.");
return;
}
So, how do I get the current user? I need to get the user's Id and email address.
Find in EF uses the argument as the key value. I don't think the Name property is the key property and therefore you always get null.
Related
I'm trying to trigger a data validation error back to my view on a lookup to a database back end.
// Perform lookup to see if domain has been taken already
var domainResults = await _context.TenantEntity.SingleOrDefaultAsync(x => x.Office365DomainName == Input.Office365DomainName);
if (domainResults.Office365DomainName == Input.Office365DomainName)
{
// duplicate domain name attempted
user.Office365DomainName = "AlreadyTaken";
return Page();
}
Here is my field:
[Required]
[Display(Name = "Office 365 Domain Name")
public string Office365DomainName { get; set; }
I'd prefer to use a DataAnnotation so I can send back a custom message to the view/user but I'm at a loss on how to build this in.
I've tried changing my property validation to a regex and watching for "AlreadyTaken" as I'm setting this inside my class which contains the same object. My thought was to perform a regex match on something obscure (like a GUID) then have my regex match that GUID for a validation error.
I'm probably over thinking all this and I hope someone has some insight.
As suggested, there was a very easy answer to this:
// Perform lookup to see if domain has been taken already
var domainResult = await _context.TenantEntity.SingleOrDefaultAsync(x => x.Office365DomainName == Input.Office365DomainName);
if (domainResult != null && domainResult.Office365DomainName == Input.Office365DomainName)
{
// duplicate domain name attempted
ModelState.AddModelError("Office365DomainName", "This domain has been registered already.");
return Page();
}
I didn't have to modify my field at all. The following article was a great help: https://exceptionnotfound.net/asp-net-mvc-demystified-modelstate/
I have a serivce that fetches a list of users from a legacy system and synchronises my AspNet Identity database. I’ve a problem when updating a user’s email address with UserManager.SetEmail(string userId, string email) and the validation fails. The user object in the UserStore retains the value of the invalid email address. I stop processing that user and skip to the next user in my list. Later when my service finds a new user to create, I use UserManager.Create(ApplicationUser user) and the database is updated with all outstanding changes including the invalid email address of the existing user.
Is there a way to stop the invalid email address being persisted? Is this a bug or am I just not using it correctly? Should I just manually take a backup of every object before any update and revert all values if the IdentityResult has an error?
//get LegacyUsers
foreach (AppUser appUser in LegacyUsers){
var user = UserManager.FindByName(appUser.userName);
if (user != null){
If (!user.Email.Equals(appUser.Email)){
var result = UserManager.setEmail(user.Id, appUser.Email)
if (!result.Succeeded){
//user object still has new value of email despite error, but not yet persisted to DB.
Log.Error(…);
continue;
}
}
}
else
{
ApplicationUser newUser = new ApplicationUser{
UserName = appUser.userName,
//etc
}
var result = UserManager.Create(newUser); //DB updates first user with new email aswell as inserting this new user
if (!result.Succeeded){
Log.Error(…);
continue;
}
}
}
I'm using version 2.2.1.40403 of Microsoft.AspNet.Identity.Core and Microsoft.AspNet.Identity.EntityFramework
This is happening because EF keeps track of models and updates all of the modified objects when SaveChanges() method is called by UserManager.Create() method. You could easily detach the user which has invalid email from the DbContext like this:
// first get DbContext from the Owin.
var context = HttpContext.GetOwinContext().Get<ApplicationDbContext>();
foreach (AppUser appUser in LegacyUsers){
var user = UserManager.FindByName(appUser.userName);
if (user != null){
If (!user.Email.Equals(appUser.Email)){
var result = UserManager.setEmail(user.Id, appUser.Email)
if (!result.Succeeded){
Log.Error(…);
// detach the user then proceed to the next one
context.Entry(user).State = EntityState.Detached;
continue;
}
}
}
else{
// rest of the code
}
}
the code below works ok, just one issue, the code confirms if user logged in is Admin or not i.e. the code checks if the user name is within the AspNetUser table and returns a Boolean true or false.
But I also need the user GarageID to be returned, the GarageID field is held within the AspNetUser table any ideas how to do this?
private bool IsUserAdmin()
{
System.Security.Principal.WindowsIdentity identity = Context.Request.LogonUserIdentity;
//Debug.WriteLine(identity.Name);
string loginName = identity.Name;
//Debug.WriteLine(loginName);
TyrescannerWebApp.IdentityModel.tyrescannerdatabaseEntities dbcontext = new TyrescannerWebApp.IdentityModel.tyrescannerdatabaseEntities();
return content.AdminUsers.Any(a => a.LoginName == loginName);
}
You should use the role provider to determine if the user is in the current role.
if (System.Web.Security.Roles.IsUserInRole(loginName, "Admin"))
{
//Do something
}
else
{
//Display unauthorized message
}
Users of my site have experienced some strange behaviour yesterday (first time I've seen this issue), and unfortunately I don't have much in the way of error logs to try to figure out what's going on. The site had a higher-than-normal number of people online at once, albeit not a large number in the grand scheme of things (maybe 50 to 100 users all trying to perform similar functions). I can't recreate the issue in my development environment, haven't seen it before, and don't really know why it is happening.
The crux of the problem is that users can register or log on successfully, but a small number of them could see other users' data.
The site is ASP.NET MVC 3.
Users are logging on and I set an authentication cookie - here's the LogOn action:
[HttpPost]
public ActionResult LogOn(AccountLogOnViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (!Membership.ValidateUser(model.UserName, model.Password))
{
ModelState.AddModelError("login-message", "Incorrect username or password");
}
}
if (ModelState.IsValid)
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
Session.Remove("MenuItems");
return Redirect(returnUrl ?? Url.Action("Index", "Home"));
}
else
{
model.ReturnUrl = returnUrl;
return View(model);
}
}
AccountLogOnViewModel is a simple object with two string properties, UserName and Password.
From what I can gather, this is fine - if you log in as NickW then doing something like User.Identity.Name correctly gives you "NickW" (when users were seeing other users' data, they reported that that "Welcome, NickW" text on screen was showing them the correct value - this is written out using User.Identity.Name)
The site also uses a custom membership provider. It overrides the ValidateLogin method, and the GetUser method. ValidateLogin appears to be working just fine so I'm not concerned about it.
The overridden GetUser method is as follows:
public override MembershipUser GetUser(string username, bool userIsOnline)
{
User user = _userRepository.Users.FirstOrDefault(u => u.UserName == username);
MembershipUser membershipUser = null;
if (user == null)
return membershipUser;
membershipUser = new MembershipUser(this.Name,
user.UserName,
user.Id,
user.Email,
null,
user.Comments,
user.IsActivated,
user.IsLockedOut,
user.CreatedDate,
user.LastLoginDate,
user.LastLoginDate,
user.LastModifiedDate,
Convert.ToDateTime(user.LastLockedOutDate));
return membershipUser;
}
So I'm attempting to retrieve a User object from my database, and using that to create a new MembershipUser object. My database User table has additional columns on top of those required by the membership provider - e.g. name, address, phone number etc.
At various points in the rest of the website (for example if you go to the Profile page), I retrieve a user object from the database and use it to populate the screen. The line I use to retrieve the User object is:
User user = userRepository.Users.FirstOrDefault(u => u.UserName == Membership.GetUser().UserName);
Here is a cut down version of the userRepository (i.e. just removing unrelated code).
public class SqlUserRepository : IUserRepository
{
private Table<User> usersTable;
private string _connectionString;
public SqlUserRepository(string connectionString)
{
_connectionString = connectionString;
usersTable = (new DataContext(connectionString)).GetTable<User>();
}
public IQueryable<User> Users
{
get { return usersTable; }
}
public void CreateUser(AccountRegisterViewModel user)
{
User newUser = new User();
newUser.UserName = user.UserName;
newUser.Salutation = user.Salutation;
newUser.PhoneNumber = user.PhoneNumber;
newUser.SecondaryPhoneNumber = user.SecondaryPhoneNumber;
newUser.FirstName = user.FirstName;
newUser.LastName = user.LastName;
newUser.PasswordSalt = CreateSalt();
newUser.Password = CreatePasswordHash(user.Password, newUser.PasswordSalt);
newUser.Email = user.Email;
newUser.CreatedDate = DateTime.UtcNow;
newUser.Comments = "Created from web registration";
newUser.LastModifiedDate = DateTime.UtcNow;
newUser.LastLoginDate = DateTime.UtcNow;
newUser.IsActivated = true;
newUser.IsLockedOut = false;
newUser.MayContact = user.MayContact;
usersTable.InsertOnSubmit(newUser);
usersTable.Context.SubmitChanges();
}
}
So it appears to me as if the auth cookie I'm setting is fine, but either:
When I first go in to the membership provider's GetUser() method, it retrieves the wrong record from the database and therefore sets up a MembershipUser object with the wrong username; subsequently when I look in the database for "this" user I'm actually looking for the wrong username.
Or: Intermittently when I do userRepository.FirstOrDefault(x => x.UserName == Membership.GetUser().Name) it retrieves the wrong record.
Or: something else is going wrong that I haven't thought of.
As I say, this seems to be a problem when the site was under load, so I'm wondering if it's some sort of caching issue somewhere? But I really don't know.
One thought I had was to change the way I retrieve the user in case the problem lies with the membership provider, and use this instead:
userRepository.FirstOrDefault(x => x.UserName == User.Identity.Name)
// or HttpContext.Current.User.Identity.Name if not within a controller
But really I'm not even sure what's going on so have no idea whether this will resolve the issue. Could it be a caching problem somewhere? It appears (but I can't be 100% certain) that when user A could see user B's details, it was always the case that user B was also active in the system (or had been within the previous 20 minutes).
I know it's a long shot, but does anyone have any idea how this could happen? Obviously it's a major concern and needs to be fixed urgently, but without knowing why it's happening I can't fix it!
Thanks in advance for any help,
Nick
Some things to consider:
Instead of using FirstOrDefault, use SingleOrDefault. FirstOrDefault assumes there will be more than 1 record of data matching your query. Since you are querying by username, there should only be 1 matching row, correct? In that case, use SingleOrDefault instead. When there are multiple rows that match the query, SingleOrDefault will throw an exception.
To get the username, instead of invoking Membership.GetUser().UserName, use User.Identity.Name. The User property on an MVC controller references an IPrincipal that should match the user's forms authentication cookie value. Since you have a custom membership provider, this should help eliminate its methods as a source of the problem.
There could be a caching issue if you have caching set up for the MVC project. Do you use the OutputCacheAttribute ([OutputCache]) on any controllers or action methods? Do you have it set up as a global filter in the global.asax file? Or do you think there may be some kind of SQL-based caching going on?
Looking at your overridden GetUser method, I see it should take 2 parameters: string username and bool isOnline. However, when you invoke it with Membership.GetUser().UserName, you are passing no parameters. Do you have another overridden overload of this method that also takes no parameters? What does it look like? Does it use System.Threading.CurrentPrincipal.Identity.Name to sniff out the current username when none is passed?
I'm trying to store a user's post into an access database through a web method. I want to store the logged-in user's username, user's post, and the post datetime.
So far, I can store an existing user post by hard coding. But I want to store posts by any logged-in users. I was told I need to get userID for username.
Thus, I've found and tried adding the following codes:
//GetUser() returns current user information
MembershipUser user = Membership.GetUser();
//Returns the UserID and converts to a string
string UserID = user.ProviderUserKey.ToString();
When I tried debugging with breakpoints, the first one was okay. But for the second one, VS 2010 said that "object reference not set to an instance of an object." How do I fix it?
VS suggested adding "new," which didn't work. It also suggested to catch NullReferenceException, but I don't know how to use the codes they provided:
public class EHClass
{
void ReadFile(int index)
{
// To run this code, substitute a valid path from your local machine
string path = #"UsersDB_in_App_Data";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}
finally
{
if (file != null)
{
file.Close();
}
}
// Do something with buffer...
}
}
Can you give me suggestions of what I need to do, or an alternative way to go about getting userID for username?
You didn't indicate what type of MembershipUser you have, but the ProviderUserKey is totally dependent on the underlying data store.
For example, the sql membership provider stores this value as a GUID.
If there is a possibility that this property won't contain any useful data, then you need to test it for existence before accessing it:
//Returns the UserID and converts to a string
string UserID;
if ((myObject != null) && (myObject.ProviderUserKey != null)) {
UserId = myObject.ProviderUserKey.ToString();
} else {
UserId = String.Empty;
}
In addition, unless you are using WSE in a straight asmx web service, I don't think that the memebership provider will have any valid data to operate on.
If this is the case, you will probably need to switch to WCF or implement WSE (NOT recommended).
The exception you're getting means that either myObject (the current user) is null or myObject.ProviderUserKey is null. I'd suggest that when you get to the breakpoint after myObject is set you should inspect the value of myObject and see whether it is null.
Depending on what is actually null affects where you look for the problem. If myObject is null then you'll need to look at the code to get the current user, and check whether someone is actually logged in etc. etc. If ProviderUserKey is null, consider whether you need this ID or would be better off with just using the username directly, check whether the membership provider actually provides that property in any meaningful way.
instead you can use this code directly....
string UserID = MembershipUser.ProviderUserKey.ToString();