When I try to log in to my development site, I get a weird error:
Invalid column name 'Email1'.
I've made derived classes for a number of different ASP.NET Identity 2.0 classes, namely:
public class MyUser : IdentityUser<int, MyLogin, MyUserRole, MyClaim>//, IUser<int>
{
#region properties
public string ActivationToken { get; set; }
public string PasswordAnswer { get; set; }
public string PasswordQuestion { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string TaxID { get; set; }
public bool IsActive { get; set; }
public bool IsApproved { get; set; }
#endregion
#region methods
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<MyUser, int> userManager)
{
var userIdentity = await userManager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
#endregion
}
The offending code is in the call to UserManager.FindAsync() in the Login method of the AccountController:
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.Email, model.Password);
if (user != null)
{
await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl);
}
ModelState.AddModelError("", "Invalid username or password.");
}
// If we got this far, something failed, redisplay form
return View(model);
}
I've designed my User table as such:
CREATE TABLE [dbo].[User]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Password] [nvarchar](50) NOT NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[Email] [nvarchar](50) NOT NULL,
[TaxID] [nvarchar](50) NULL,
[PaymentMethodID] [int] NULL,
[IsActive] [bit] NOT NULL DEFAULT 1,
[IsApproved] [bit] NOT NULL,
[IsLocked] [bit] NOT NULL,
[CreationDate] [datetime] NULL,
[ApprovalDate] [datetime] NULL DEFAULT NULL,
[LastLoginDate] [datetime] NULL,
[PasswordQuestion] [nvarchar](max) NULL,
[PasswordAnswer] [nvarchar](max) NULL,
[ActivationToken] [nvarchar](200) NULL,
[EmailConfirmed] [bit] NOT NULL,
[SecurityStamp] [nvarchar](max) NULL,
[PhoneNumber] [nvarchar](50) NULL,
[PhoneNumberConfirmed] [bit] NOT NULL,
[TwoFactorEnabled] [bit] NOT NULL,
[LockoutEndDateUtc] [datetime2](7) NULL,
[LockoutEnabled] [bit] NOT NULL,
[AccessFailedCount] [int] NOT NULL,
CONSTRAINT [User_PK] PRIMARY KEY NONCLUSTERED ([ID]),
CONSTRAINT [Email_UK] UNIQUE NONCLUSTERED([Email])
)
And I'm binding my MyUser class to that table in the OnModelCreating method of MyDbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Map Entities to their tables.
modelBuilder.Entity<MyUser>().ToTable("User");
modelBuilder.Entity<MyRole>().ToTable("Role");
modelBuilder.Entity<MyClaim>().ToTable("UserClaim");
modelBuilder.Entity<MyLogin>().ToTable("UserLogin");
modelBuilder.Entity<MyUserRole>().ToTable("UserRole");
// Set AutoIncrement-Properties
modelBuilder.Entity<MyUser>().Property(r => r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<MyClaim>().Property(r => r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<MyRole>().Property(r => r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
// Override some column mappings that do not match our default
modelBuilder.Entity<MyUser>().Property(r => r.UserName).HasColumnName("Email");
modelBuilder.Entity<MyUser>().Property(r => r.PasswordHash).HasColumnName("Password");
}
Somewhere Identity 2.0 is creating another Email column that it shouldn't. Any thoughts?
There's already a column with name Email
in the default schema.
As @enki.dev suggest in his deleted answer if you look at the definition for IdentityUser you have those properties already defined.
You're doing something quite dangerous here:
modelBuilder.Entity<MyUser>().Property(r => r.UserName).HasColumnName("Email");
modelBuilder.Entity<MyUser>().Property(r => r.PasswordHash).HasColumnName("Password");
as you're trying to force one column into another. The property Email has been used extensively in this framework for password retrieval etc etc.
You can try and rename it
modelBuilder.Entity<MyUser>().Property(r => r.Email).HasColumnName("Blah");
so you wouldn't have the duplicate; but I guess you're going to face many other problems on the way.
Why don't you simply store the email in the UserName
property ?
Another suggestion; it's always better to let the framework create the tables for you using the migration so you always know what's happening.
From Visual Studio choose menu
select your project in the combo: Default Project.
Run Enable-Migrations
.
It should create a folder called Migrations
with a file called Configuration.cs
.
The constructor should look like this:
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
change the value AutomaticMigrationsEnabled
to true
.
go back to Package Manager Console
and run
Update-Database
or
Update-Database -Force
to recreate the whole schema for you tables.
There's a protected method there where you can see your data:
protected override void Seed(ASPNETIdentity2.Models.MyContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}