I'm rewriting an MVC3 application using MVC5 with EF6 and attempting to also migrate the membership and roles API to Identity 2. I've followed several guides but am now receiving build errors with which I need assistance.
My AccountController in part is as follows:
[Authorize]
public class AccountController : Controller
{
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
My UserManager is as follows:
public class UserManager : UserManager<User>
{
public UserManager()
: base(new UserStore<User>(new ApplicationDbContext()))
{
this.PasswordHasher = new SQLPasswordHasher();
}
}
My ApplicationDbContext is as follows:
public class ApplicationDbContext : IdentityDbContext<User>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
this.Database.Log = Logger;
}
private void Logger(string log)
{
Debug.WriteLine(log);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var application = modelBuilder.Entity<Application>();
application.HasKey(t => t.ApplicationId).ToTable("Applications");
modelBuilder.Entity<UserDbProfile>().ToTable("Profiles");
}
public virtual IDbSet<Application> Applications { get; set; }
public virtual IDbSet<UserDbProfile> Profiles { get; set; }
}
My User model is as follows:
public class User : IdentityUser
{
public User()
{
CreateDate = DateTime.UtcNow;
IsApproved = false;
LastLoginDate = DateTime.UtcNow;
LastActivityDate = DateTime.UtcNow;
LastPasswordChangedDate = DateTime.UtcNow;
LastLockoutDate = MinSqlDate;
FailedPasswordAnswerAttemptWindowStart = MinSqlDate;
FailedPasswordAttemptWindowStart = MinSqlDate;
Profile = new ProfileInfo();
}
public System.Guid ApplicationId { get; set; }
public bool IsAnonymous { get; set; }
public System.DateTime? LastActivityDate { get; set; }
public string Email { get; set; }
public string PasswordQuestion { get; set; }
public string PasswordAnswer { get; set; }
public bool IsApproved { get; set; }
public bool IsLockedOut { get; set; }
public System.DateTime? CreateDate { get; set; }
public System.DateTime? LastLoginDate { get; set; }
public System.DateTime? LastPasswordChangedDate { get; set; }
public System.DateTime? LastLockoutDate { get; set; }
public int FailedPasswordAttemptCount { get; set; }
public System.DateTime? FailedPasswordAttemptWindowStart { get; set;}
public int FailedPasswordAnswerAttemptCount { get; set; }
public System.DateTime? FailedPasswordAnswerAttemptWindowStart
{ get; set; }
public string Comment { get; set; }
public ProfileInfo Profile { get; set; }
private static readonly DateTime MinSqlDate =
DateTime.Parse("1/1/1754");
}
The specific errors received are similar to:
Error 16
Inconsistent accessibility: parameter type
'Microsoft.AspNet.Identity.UserManager' is less accessible than method
'Controllers.AccountController.AccountController(Microsoft.AspNet.
Identity.UserManager<Controllers.ApplicationUser>)'
Note that I've already created new tables in the database that migrated the old membership and roles for use with Identity 2.
What must be done to resolve the errors and ensure that the new Identity 2 methods are working correctly?
Update
My AccountController code is now as follows:
public AccountController()
: this(new UserManager(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
UserManager is as follows, in part:
public class UserManager : UserManager<User>
{
private UserStore<Controllers.ApplicationUser> userStore;
public UserManager()
: base(new UserStore<User>(new ApplicationDbContext()))
{
this.PasswordHasher = new SQLPasswordHasher();
}
}
Build error states:
Error 19 'UserManager' does not contain a constructor that takes 1 arguments
Note that the ApplicationUser controller was created but doesn't have any methods implemented. Is this controller, needed? Or, can I remove it and references to it?
Your AccountController needs to take your UserManager, not UserManager<ApplicationUser> which is part of the framework:
[Authorize]
public class AccountController : Controller
{
public AccountController()
: this(new UserManager(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager userManager)
{
UserManager = userManager;
}
public UserManager UserManager { get; private set; }
Also I noticed that in controller you have ApplicationUser, but your user object is actually User. Make sure you are consistent with your classes.
Related
How should I update custom made identity fields in ASP.NET MVC?
public class ApplicationUser : IdentityUser
{
public string customerName { get; set; }
public string customer_lastName { get; set; }
public string customer_phoneNumber { get; set; }
public string addressType { get; set; }
public string addressLine1 { get; set; }
public string addressLine2 { get; set; }
public string city { get; set; }
public string country { get; set; }
public string[] location_details { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
To be more specific, how am I supposed to update fields such as customerName,or customer_lastName after a value has been inserted in database for that field ?
I have been able to implement Breeze into an angular application using AspNetCore based on the Breeze Temphire sample and the breeze.server.net/AspNetCore/ github samples. I am stuck trying to figure out how to implement EFContextProvider in a Unit Of Work. Referring to the Tempire Code Temphire on Github, can someone show me how to create a UnitOfWork using AspNetCore?
EFContextProvider does not exist in the following breeze libs:
Breeze.Core
Breeze.Persistence
Breeze.pErsistence.EFCore
Breeze.AspNetCore.NetCore
To be clear I would like to create the following using the AspNetCore/Breeze libs:
public class UnitOfWork
{
private readonly EFContextProvider<TempHireDbContext> _contextProvider;
public UnitOfWork()
{
_contextProvider = new EFContextProvider<TempHireDbContext>();
StaffingResources = new Repository<StaffingResource>(_contextProvider.Context);
Addresses = new Repository<Address>(_contextProvider.Context);
AddressTypes = new Repository<AddressType>(_contextProvider.Context);
PhoneNumbers = new Repository<PhoneNumber>(_contextProvider.Context);
PhoneNumberTypes = new Repository<PhoneNumberType>(_contextProvider.Context);
Rates = new Repository<Rate>(_contextProvider.Context);
RateTypes = new Repository<RateType>(_contextProvider.Context);
Skills = new Repository<Skill>(_contextProvider.Context);
States = new Repository<State>(_contextProvider.Context);
WorkExperienceItems = new Repository<WorkExperienceItem>(_contextProvider.Context);
StaffingResourceListItems = new StaffingResourceListItemRepository(_contextProvider.Context);
}
public IRepository<StaffingResource> StaffingResources { get; private set; }
public IRepository<Address> Addresses { get; private set; }
public IRepository<AddressType> AddressTypes { get; private set; }
public IRepository<PhoneNumber> PhoneNumbers { get; private set; }
public IRepository<PhoneNumberType> PhoneNumberTypes { get; private set; }
public IRepository<Rate> Rates { get; private set; }
public IRepository<RateType> RateTypes { get; private set; }
public IRepository<Skill> Skills { get; private set; }
public IRepository<State> States { get; private set; }
public IRepository<WorkExperienceItem> WorkExperienceItems { get; private set; }
public IStaffingResourceListItemRepository StaffingResourceListItems { get; private set; }
public SaveResult Commit(JObject changeSet)
{
return _contextProvider.SaveChanges(changeSet);
}
}
}
Could it be as simple as the following?
private readonly EFPersistenceManager<DictionaryPortalContext> _contextProvider;
Thanks!
Pretty close.
We usually create a separate class so that you have somewhere to add 'BeforeSaveEntities' and 'AfterSaveEntities' methods.
public class MyPersistenceManager : EFPersistenceManager<DictionaryPortalContext> {
public MyPersistenceManager (DictionaryPortalContext dbContext) : base(dbContext) {
// PM methods here.
}
and then
[Route("breeze/[controller]/[action]")]
[BreezeQueryFilter]
public class MyController : Controller {
private MyPersistenceManager PersistenceManager;
// called via DI
public MyController(NorthwindIBContext_CF context) {
PersistenceManager = new MyPersistenceManager(context);
}
[HttpGet]
public IActionResult Metadata() {
return Ok(PersistenceManager.Metadata());
}
[HttpPost]
public SaveResult SaveChanges([FromBody] JObject saveBundle) {
return PersistenceManager.SaveChanges(saveBundle);
}
...
}
Hope this helps.
Why db.Countries() comes null in following scenario-
1. CityController
[Authorize]
public class CityController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext("CP");
// GET: City/Create
public ActionResult Create()
{
ViewBag.CountryId = new SelectList(db.Countries.ToList(), "CountryId", "Name");
return View();
}
ApplicationDbContext
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
internal IDbSet<Country> Countries { get; set; }
...
}
Country is defined as-
[Table("Country")]
public class Country
{
#region Fields
private ICollection<City> _cities;
#endregion
#region Scalar Properties
public Guid CountryId { get; set; }
public string Name { get; set; }
public string CountryCode { get; set; }
#endregion
#region Navigation Properties
public virtual ICollection<City> Cities
{
get { return _cities ?? (_cities = new List<City>()); }
set { _cities = value; }
}
#endregion
}
City is defined as-
[Table("City")]
public class City
{
#region Fields
private ICollection<Location> _locations;
#endregion
#region Scalar Properties
public Guid CityId { get; set; }
public Guid CountryId { get; set; }
public string Name { get; set; }
public string CityCode { get; set; }
public string ZipCode { get; set; }
public Country Country { get; set; }
#endregion
#region Navigation Properties
public virtual ICollection<Location> Locations
{
get { return _locations ?? (_locations = new List<Location>()); }
set { _locations = value; }
}
#endregion
}
What could be the reason for not populating Country table records and returning countries to null?
After sparing few hours, I just noticed the Access-modifier of Countries properties which was internal. I made it Public and magic happened! It works though I don't have any explanation on WHY part of it.
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
//internal IDbSet<Country> Countries { get; set; }
public IDbSet<Country> Countries { get; set; }
public IDbSet<City> Cities { get; set; }
Thanks everyone.
I have my Accountmodels.cs class like this---
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
}
public class RegisterExternalLoginModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
public string ExternalLoginData { get; set; }
}
and my User Profile class is like this---
public class UserProfile
{
public UserProfile()
{
this.Posts = new HashSet<Post>();
}
public int UserId { get; set; }
public string UserName { get; set; }
public string AvatarExt { get; set; }
public virtual ICollection<Post> Posts { get; set; }
and finally my dbContext class is----
public class WallEntities : DbContext
{
public WallEntities()
: base("name=WallEntities")
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<UserProfile> UserProfiles { get; set; }
I am using both WallEntities and DefaultConnection as name in connection string.I am using Simple Membership so i have a InitializeSimpleMembershipAttribute.cs File.Its look like this---
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}.
My Problem is that It is creating two tables in Sql server.One is UserProfile and another is UserProfiles table.I want to create only 1 table that is UserProfile table with UserId,UserName and AvatarExt Property.After registration, it should store all information.
I want to answer my question is it may be useful for someone---
Just The problem here was not to use the two DbContext.Instead of that, for the code First approach one dbContext is enough.
So, DbContext should be like this----
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
public DbSet<Post> Posts { get; set; }
it should not be here
// public DbSet<UserProfile> UserProfiles { get; set; }
}
and romove that WallEntities DbContext. and reomove USerFrofile from UserContext as i have commented out and also change all the corresponding codes in the same way.
I added a new property called ResetPassword to the "out of the box" ApplicationUser class but when I run "add-migration" the up/down methods in the auto generated migration class are blank and when I try to log on to the application the following error is raised "The model backing the 'ApplicationDbContext' context has changed since the database was created. Consider using Code First Migrations to update the database".
This is my code:
public class ApplicationUser : IdentityUser
{
public bool ResetPassword { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
May DAL class looks like this:
public class DefaultConnection : DbContext
{
public DefaultConnection()
: base("DefaultConnection")
{
this.Configuration.ProxyCreationEnabled = false;
this.Configuration.LazyLoadingEnabled = false;
}
public DbSet<Category> Categories { get; set; }
public DbSet<Group> Groups { get; set; }
public DbSet<Model> Models { get; set; }
public DbSet<Variable> Variables { get; set; }
public DbSet<Column> Columns { get; set; }
public DbSet<Project> Projects { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Config> Configs { get; set; }
public DbSet<Target> Targets { get; set; }
public DbSet<Organisation> Organisations { get; set; }
public DbSet<OrgGroup> OrgGroups { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
When logging on this is the line which throws the error:
var userManager = context.OwinContext.GetUserManager();
You have 2 contexts in your application. When you run migrations, you need to specify type of context you want migration for:
Add-Migration -configuration <Namespace>.ApplicationDbContext <Migrations-Name>
See this page for more details about using migrations with multiple DbContexts in the same assembly.