How to fix Db after invalid column name, and migration failed - c#

I added properties to the ApplicationUser.cs (which I've done before) and everything exploded. This class extends IdentityUser. When I comment out the properties everything appears to work fine. What did I do wrong?
ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
public string LGID { get; } = "";
public string CoIDs { get; } = "";
public string LGIDSuperUserName { get; set; } = "unknown"; //new
public bool IsSuperUser { get; set; } = false; //new
public ApplicationUser() { }
public ApplicationUser(ClaimsIdentity identity)
{
IEnumerable<Claim> claims = identity.Claims;
foreach (Claim c in claims)
{
if (c.Type == "LGID")
LGID = c.Value;
if (c.Type == "CoIDs")
CoIDs = c.Value;
if (c.Type == "LGIDSuperUser")
LGIDSuperUserName = c.Value;
if (c.Type == "IsSuperUser")
IsSuperUser = c.Value.ToLower()=="yes";
}
}
}
More info if needed. Not sure whats relevant here
When I go to login to my site I first got an error that suggested I needed to migrate the DB. In NuGet Package Manager I ran:
Add-Migration ApplicationDbContext
Update-Database
Now the error message when I try to login says:
Invalid column name 'IsSuperUser'.
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
Here is my Migrations folder inside VisualStudio:

Related

Asp.Net Core Web API - Error CS0747 Invalid initializer member declarator

I have this code in ASP.NET Core Web API:
DTO:
public class AuthRequest
{
public string Email { get; set; }
public string Password { get; set; }
}
public class AuthResponse
{
public string Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Token { get; set; }
}
Services:
public interface IAuthService
{
Task<AuthResponse> Login(AuthRequest request);
}
public async Task<AuthResponse> Login(AuthRequest request)
{
var user = await _userManager.FindByEmailAsync(request.Email);
if (user == null)
{
throw new Exception($"User with {request.Email} not found.");
}
var result = await _signInManager.PasswordSignInAsync(user.UserName, request.Password, false, lockoutOnFailure: false);
if (!result.Succeeded)
{
throw new Exception($"Credentials for '{request.Email} aren't valid'.");
}
JwtSecurityToken jwtSecurityToken = await GenerateToken(user);
var roles = await _userManager.GetRolesAsync(user);
AuthResponse response = new AuthResponse
{
Id = user.Id,
Token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken),
Email = user.Email,
UserName = user.UserName,
roles,
};
return response;
}
From the code above, I want to include roles of the logged in user in the AuthResponse. So I added, roles
But I got this error:
Error CS0747 Invalid initializer member declarator
roles is highlighted.
How do I resolve this?
Thanks
Notice how this property initialization:
roles,
differs from the rest:
Id = user.Id,
Token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken),
Email = user.Email,
UserName = user.UserName,
You need to specify which property is being set. For example, is there a Roles property (which matches the type)? If so, it would be something like this:
Roles = roles,
Basically, whatever property you're trying to initialize in the resulting object, you need to indicate the name of that property in its initialization.

How to check phone number is unique in AspNetUsers table when using ASP.NET Web Api

I have created an Asp.Net Web Api project and used Individual user accounts.
When I am adding users to the table the default system automatically checks if the email address supplied already exists in the table, if so a bad request is thrown otherwise the user can be submitted.
How can I also check if the Phone Number is unique and hasn't already been submitted to the table?
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
**using (ApplicationDbContext db = new ApplicationDbContext())
{
var foundPhoneNumber = await db.Users.FirstOrDefaultAsync(x => x.PhoneNumber.Equals(model.PhoneNumber));
if (foundPhoneNumber != null)
{
return BadRequest("Phone number already exists");
}
}**
var user = new ApplicationUser()
{
UserName = model.Email,
Email = model.Email,
PhoneNumber = model.PhoneNumber,
FirstName = model.FirstName,
LastName = model.LastName,
MemberNumber = model.MemberNumber,
CarReg = model.CarReg
};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
I have queried the database to check if there is a Phone Number with the same number. This works, but is there a better way to do this?
Modify your ApplicationUser call and add the following attributes.
public class ApplicationUser : IdentityUser
{
[MaxLength(17)]
[IsUnique]
public string PhoneNumber { get; set; }
}
You can override ValidateEntity method in ApplicationUserDbContext class, it will trigger on SaveChanges method.
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
if (entityEntry != null && entityEntry.State == EntityState.Added)
{
var errors = new List<DbValidationError>();
////User Validation
if (entityEntry.Entity is ApplicationUser user)
{
if (this.Users.Any(u => string.Equals(u.PhoneNumber, user.PhoneNumber)))
{
errors.Add(new DbValidationError("User",
string.Format($"Phonenumber {user.PhoneNumber} is already taken")));
}
}
if (errors.Any())
{
return new DbEntityValidationResult(entityEntry, errors);
}
}
return new DbEntityValidationResult(entityEntry, new List<DbValidationError>());
}
Validation can be added via a custom ValidationAttribute that you add to the PhoneNumber property on you model. Here is a simple example:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class NotABananaAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
var inputValue = value as string;
var isValid = true;
if (!string.IsNullOrEmpty(inputValue))
{
isValid = inputValue.ToUpperInvariant() != "BANANA";
}
return isValid;
}
}
And its used liked this...
public class Model
{
[NotABanana(ErrorMessage = "Bananas are not allowed.")]
public string FavoriteFruit { get; set; }
}
Example sourced from:
https://riptutorial.com/csharp/example/18486/creating-a-custom-validation-attribute

Issue with returning object from a function in asp.net MVC

i am little confused about my code:
Here is some function from my controller:
public void signIn(string userName, string userPass)
{
User user = new User();
user.getUser(userName , userPass);
if (user.userName != null)
{
Response.Redirect("/Home/Menu");
}
else
{
Response.Redirect("/Index/Index?Fail=" + "fail");
}
}
the " user.getUser" suppose to return a User object.. here is the code from my Model directory:
public class User
{
public ObjectId _id { get; set; }
public string userName { get; set; }
public string userPass { get; set; }
public User getUser(string name , string pass)
{
var client = new MongoClient("mongodb://localhost:27017");
var db = client.GetDatabase("testdb");
var coll = db.GetCollection<User>("user");
List<User> list = coll.Find(x => x.userName == name && x.userPass == pass).ToList<User>();
User uObj = new User();
uObj = list.FirstOrDefault();
return uObj;
}
}
when i am debugging the code i can see the uJob object contain values. but when the function end and i return to the controller i see that the user object contain only null values, and the condition - " if (user.userName != null)" is returning FALSE!.. instead of TRUE..
i would like to get some help. Thanks !
You have to assign it.
user = user.getUser(userName , userPass);
Either you assign the value returned by the getUser method in calling program like this
user = user.getUser(userName , userPass);
Or you change the code in Model like this
public class User
{
public ObjectId _id { get; set; }
public string userName { get; set; }
public string userPass { get; set; }
public void getUser(string name , string pass)
{
var client = new MongoClient("mongodb://localhost:27017");
var db = client.GetDatabase("testdb");
var coll = db.GetCollection<User>("user");
var user = coll.FirstOrDefault(x => x.userName == name && x.userPass == pass);
if(user != null)
{
this._id = user._id;
this.userName = user.userName;
this.userPass = user.userPass;
}
}
}
if you replace
if (user.userName != null)
with
if ( user.getUser(userName , userPass).userName != null)
wil works for you.

How to perform addition, update operation on extra table in identity server?

I have added the following UserLog table in the database using asnetidentity but i don't know how to perform add,update operation on the table.
public class User : IdentityUser
{
public virtual ICollection<UserLog> UserLogs { get; set; }
}
public class Context : IdentityDbContext<User, Role, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
{
public Context(string connString)
: base(connString)
{
}
}
public class UserLog
{
[Key]
public Guid UserLogID { get; set; }
public string IPAD { get; set; }
public DateTime LoginDate { get; set; }
public string UserId { get; set; }
[ForeignKey("UserId")]
public virtual ApplicationUser User { get; set; }
}
public System.Data.Entity.DbSet<UserLog> UserLog { get; set; }
Like in the following code, I am using inbuilt methods of these aspnetidentity tables but how to add an entry in the "UserLog" table when user login every time in the following method?
public override async Task AuthenticateLocalAsync(LocalAuthenticationContext ctx)
{
var username = ctx.UserName;
var password = ctx.Password;
var message = ctx.SignInMessage;
ctx.AuthenticateResult = null;
if (userManager.SupportsUserPassword)
{
var user = await FindUserAsync(username);
if (user != null)
{
if (userManager.SupportsUserLockout &&
await userManager.IsLockedOutAsync(user.Id))
{
return;
}
if (await userManager.CheckPasswordAsync(user, password))
{
if (userManager.SupportsUserLockout)
{
await userManager.ResetAccessFailedCountAsync(user.Id);
}
var result = await PostAuthenticateLocalAsync(user, message);
if (result == null)
{
var claims = await GetClaimsForAuthenticateResult(user);
result = new AuthenticateResult(user.Id.ToString(), await GetDisplayNameForAccountAsync(user.Id), claims);
}
ctx.AuthenticateResult = result;
}
else if (userManager.SupportsUserLockout)
{
await userManager.AccessFailedAsync(user.Id);
}
}
}
}
Step 1: Create an instance of UserLog
var userLog = new UserLog() { /* Set value for all the properties here */ };
Step 2: Add instance of UserLog to DbContext
context.Set<UserLog>().Add(userLog);
Step 3: Call DbContext.SaveChanges() to save changes to database.
context.SaveChanges();
Complete source code will looks like:
var userLog = new UserLog {
UserLogID = Guid.NewGuid(),
IPAD = "Some Value",
LoginDate = DateTime.Now,
UserId = "User Id Here"
};
var context = new Context();
context.Set<UserLogs>().Add(userLog);
context.SaveChanges();

asp.net identity userName is unique?

I was reading about user Identity in Microsoft and trying to apply them in my MVC5 app.
Up to my knowledge the Id is the key, while the userName is not key and the definition says that it can be null,
so I was asking myself... why in the MVC5 project template, when you enter an already existing userName you will receive an Error message ??
I tried to reach to the userName validation but I couldn't.
Here is the database definition:
CREATE TABLE [dbo].[AspNetUsers] (
[Id] NVARCHAR (128) NOT NULL,
[UserName] NVARCHAR (MAX) NULL,
and here is the IdentityUser definition, notice (no validation):
namespace Microsoft.AspNet.Identity.EntityFramework
{
public class IdentityUser : IUser
{
public IdentityUser();
public IdentityUser(string userName);
public virtual ICollection<IdentityUserClaim> Claims { get; }
public virtual string Id { get; set; }
public virtual ICollection<IdentityUserLogin> Logins { get; }
public virtual string PasswordHash { get; set; }
public virtual ICollection<IdentityUserRole> Roles { get; }
public virtual string SecurityStamp { get; set; }
public virtual string UserName { get; set; }
}
}
and on registration, the UserManager.CreateAsync method is called, here is the definition:
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
and this is the last thing I reach regarding CreateAsync:
public virtual Task<IdentityResult> CreateAsync(TUser user, string password);
I don't see validation anywhere in the code, however it won't allow you to enter an existing userName.
I think understanding how does this works will improve my experience with the Identity concept of asp.net and will improve my code.
Any guidance is highly appreciated
This happens in IdentityDbContext<TUser>, which your ApplicationDbContext probably inherits from. It overrides DbContext's ValidateEntity method to do the check. See this decompiled code:
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
if ((entityEntry != null) && (entityEntry.State == EntityState.Added))
{
TUser user = entityEntry.Entity as TUser;
if ((user != null) && this.Users.Any<TUser>(u => string.Equals(u.UserName, user.UserName)))
{
return new DbEntityValidationResult(entityEntry, new List<DbValidationError>()) { ValidationErrors = { new DbValidationError("User", string.Format(CultureInfo.CurrentCulture, IdentityResources.DuplicateUserName, new object[] { user.UserName })) } };
}
IdentityRole role = entityEntry.Entity as IdentityRole;
if ((role != null) && this.Roles.Any<IdentityRole>(r => string.Equals(r.Name, role.Name)))
{
return new DbEntityValidationResult(entityEntry, new List<DbValidationError>()) { ValidationErrors = { new DbValidationError("Role", string.Format(CultureInfo.CurrentCulture, IdentityResources.RoleAlreadyExists, new object[] { role.Name })) } };
}
}
return base.ValidateEntity(entityEntry, items);
}
If you don't want this behavior you can inherit from DbContext directly.
When I'm looking at the example of ASP.NET Identity (https://www.nuget.org/packages/Microsoft.AspNet.Identity.Samples) I noticed that they use a UserValidator which is default set to RequireUniqueEmail = true;
The example uses the following code to set the RequireUniqueEmail property to true.
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
return manager;
}
Perhaps this is the reason that the username is unique in your MVC application.
Try setting the property to false!?

Categories

Resources