Reputation: 3382
The schema updates fine, but the seed method doesn't run because of a NullReferenceException. Everything else seems to be fine, including being able to issue tokens for password resets and so forth while the site is running. It just does this when the Seed method runs. I think I only started getting this after adding the DataProtectorTokenProvider stuff. Any ideas?
EDIT: and of course this NullReferenceException shouldn't be happening at all, so What is a NullReferenceException, and how do I fix it? is irrelevant here.
EDIT: or maybe it's not. Am I missing something really fundamental here? This line of code:
UserTokenProvider = new DataProtectorTokenProvider<AppUser> (dataProtectionProvider.Create("ASP.NET Identity")) { TokenLifespan = TimeSpan.FromDays(90d) };
Can the DataProtectorTokenProvider instantiation ever result in anything other than null during the Seed method because the site/app isn't running/hasn't started and that's just how OWIN works? Thanks.
Here is the output from the PMC:
Running Seed method.
System.NullReferenceException: Object reference not set to an instance of an object.
at Identity.AppUserManager..ctor(IUserStore`1 store) in Identity\AppUserManager.cs:line 25
at Migrations.Configuration.Seed(EFDbContext context) in Migrations\Configuration.cs:line 49
at System.Data.Entity.Migrations.DbMigrationsConfiguration`1.OnSeed(DbContext context)
at System.Data.Entity.Migrations.DbMigrator.SeedDatabase()
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.SeedDatabase()
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClassc.b__b()
at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
Object reference not set to an instance of an object.
Here is the configuration code:
internal sealed class Configuration: DbMigrationsConfiguration<Website.Domain.Concrete.EFDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "Website.Domain.Concrete.EFDbContext";
}
protected override void Seed(Concrete.EFDbContext context)
{
// This line is where we hit the exception
AppUserManager userManager = new AppUserManager(new UserStore<AppUser>(context));
AppRoleManager roleManager = new AppRoleManager(new RoleStore<AppRole>(context));
...
And here is the AppUserManager code:
public class AppUserManager : UserManager<AppUser>
{
public AppUserManager(IUserStore<AppUser> store)
: base(store)
{
IDataProtectionProvider dataProtectionProvider = IdentityConfig.DataProtectionProvider;
// This is causing the NullReferenceException
UserTokenProvider = new DataProtectorTokenProvider<AppUser>(dataProtectionProvider.Create("ASP.NET Identity")) { TokenLifespan = TimeSpan.FromDays(90d) };
}
public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
{
EFDbContext db = context.Get<EFDbContext>();
AppUserManager manager = new AppUserManager(new UserStore<AppUser>(db));
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 8,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = false,
RequireUppercase = false
};
manager.UserValidator = new UserValidator<AppUser>(manager)
{
AllowOnlyAlphanumericUserNames = true,
RequireUniqueEmail = true
};
return manager;
}
}
And here is the IdentityConfig file. I have this instead of a startup file and I tell Owin to run it on startup with this key in appsettings in the web.config
<add key="owin:AppStartup" value="Website.Domain.App_Start.IdentityConfig" />:
namespace Website.Domain.App_Start
{
public class IdentityConfig
{
public static IDataProtectionProvider DataProtectionProvider { get; set; }
public void Configuration(IAppBuilder app)
{
DataProtectionProvider = app.GetDataProtectionProvider();
app.CreatePerOwinContext<EFDbContext>(EFDbContext.Create);
app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create);
app.CreatePerOwinContext<AppSignInManager>(AppSignInManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/account/login")
});
}
}
}
Upvotes: 0
Views: 1362
Reputation: 3382
It was failing because
IDataProtectionProvider dataProtectionProvider = IdentityConfig.DataProtectionProvider;
will return null unless the app is actually running. Therefore this fails during a Migration.
Here's the fix:
if (dataProtectionProvider != null)
{
UserTokenProvider = new DataProtectorTokenProvider<AppUser>(dataProtectionProvider.Create("ASP.NET Identity")) { TokenLifespan = TimeSpan.FromDays(90d) };
}
Upvotes: 2