I have been struggling with the new Forms Identity process Microsoft introduced with the One Asp.Net implementation -- in particular with regards to Asp.NET MVC5.
My issues are twofold:
How to point the context to a regular SQL instance instead of the LocalDb. At the very least LocalDb is not viable for me since my hosting provider does not support it.
How to use a custom database for my identity entities.
I realize I could just change the connection string for the "DefaultConnection" entry in the Web.Config. But that still leaves me a series of tables prefixed with "AspNet" or some such.
Under the old MembershipProvider architecture, you could inherit from the providers and implement everything you needed in any way you want by placing entries in the Web.config that pointed the Forms Authentication process to your custom membership process.
With the new identity process, however, there are no hooks in the web.config to use. Additionally, inheriting from it is not any good as nothing appears to be virtual and to top it all off, it is inheriting from an existing context to boot.
I tried using my own context with entities implementing the appropriate new interfaces, but all it did was ignore my context completely and not only that, use localdb with a default DefaultConnection Connection String, ignoring my own context.
Since this is a new Microsoft brainchild, there are no real walkthroughs on how to customize the new process, just demos on how great the new process is.
I came across one entry out in the web that mentioned rolling out your own identity process and connect it to the OWIN process, but I am totally unfamiliar with OWIN and would need at least some info on how this could be done. (My initial foray into the OWIN project is not yielding any results)
Does anyone have any info?
Go to solution explorer => Views Folder => Right-click on “Home” Folder >> go to “Add” >> Click on [New Item] as follow. MVC 5 View Page(Razor) template from "Add New Item" window and provide the required name like "Index. cshtml" click on "Add" button.
Now, open the Startup configurations and add below code under ConfigureServices. This code will setup the database context. The second line configures the database which should be used for identity. AddIdentity(IServiceCollection) adds the default identity system configuration for the specified User and Role types.
Update: I am completely rewriting my answer because I have learned so much more about this process and realized that my answer was nowhere near complete enough.
First I created my entities, inheriting from the IdentyXXX classes of Identity (Only supplying one here for sample):
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using NTier.Web.Core.Interfaces.Common;
using NTier.Web.Core.Interfaces.DataModels;
using NTier.Web.Core.Interfaces.Stores;
namespace NTier.Web.DataAccess.Entities
{
public sealed class MemberEntity : IdentityUser<Guid, MemberLogin, MemberRole, MemberClaim>,
IMemberDataModel, IAuditable
{
public MemberEntity()
{
Id = Guid.NewGuid();
}
#region Overrides of IdentityUser<Guid,MemberLogin,MemberRole,MemberClaim>
public override Guid Id
{
get { return base.Id; }
set
{
base.Id = value != Guid.Empty ? value : base.Id;
}
}
#region Overrides of IdentityUser<Guid,MemberLogin,MemberRole,MemberClaim>
public override string PasswordHash
{
get { return base.PasswordHash; }
set
{
base.PasswordHash = !string.IsNullOrWhiteSpace(value) ? value : base.PasswordHash ;
}
}
#endregion
#endregion
public Guid Identity
{
get { return Id; }
set
{
if (value != Guid.Empty)
{
Id = value;
}
}
}
public string Moniker { get; set; }
[MaxLength(256)]
public string FirstName { get; set; }
[MaxLength(256)]
public string LastName { get; set; }
[MaxLength(256)]
public string Middle { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<MemberEntity, Guid> 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;
}
#region Implementation of IAuditable
public DateTime DateTimeCreated { get; set; }
public DateTime? DateTimeModified { get; set; }
public DateTime? DateTimeDeleted { get; set; }
public DateTime? DateTimeArchived { get; set; }
public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
public string DeletedBy { get; set; }
public string ArchivedBy { get; set; }
public bool IsDeleted { get; set; }
public bool IsArchived { get; set; }
#endregion
}
}
Second, I overrode the OnModelCreating method in my DbContext like so:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (modelBuilder == null) throw new ArgumentNullException("modelBuilder");
modelBuilder.Entity<WebSiteEntity>()
.HasKey(site => site.Identity)
.ToTable("WebSite");
#region Security
modelBuilder.Entity<MemberEntity>()
.ToTable("Member")
.HasMany(u => u.Roles)
.WithRequired()
.HasForeignKey(ur => ur.UserId);
modelBuilder.Entity<MemberEntity>()
.HasMany(u => u.Claims)
.WithRequired()
.HasForeignKey(uc => uc.UserId);
modelBuilder.Entity<MemberEntity>()
.HasMany(u => u.Logins)
.WithRequired()
.HasForeignKey(ul => ul.UserId);
modelBuilder.Entity<MemberEntity>()
.Property(u => u.Moniker)
.HasMaxLength(50)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("UserNameIndex")
{
IsUnique = true,
IsClustered = false,
Order = 2
}))
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("MonikerIndex")
{
IsUnique = true,
IsClustered = false,
Order = 1
}));
modelBuilder.Entity<MemberEntity>()
.Property(u => u.LastName)
.HasMaxLength(256)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("UserNameIndex")
{
IsUnique = true,
IsClustered = false,
Order = 3
}))
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("MonikerIndex")
{
IsUnique = true,
IsClustered = false,
Order = 2
}));
;
modelBuilder.Entity<MemberEntity>()
.Property(u => u.FirstName)
.HasMaxLength(256)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("UserNameIndex")
{
IsUnique = true,
IsClustered = false,
Order = 4
}))
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("MonikerIndex")
{
IsUnique = true,
IsClustered = false,
Order = 3
}));
;
modelBuilder.Entity<MemberEntity>()
.Property(u => u.Middle)
.HasMaxLength(256);
modelBuilder.Entity<MemberEntity>()
.Property(u => u.UserName)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("UserNameIndex")
{
IsUnique = true,
IsClustered = false,
Order = 1
}))
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("MonikerIndex")
{
IsUnique = true,
IsClustered = false,
Order = 4
}));
modelBuilder.Entity<MemberEntity>()
.Property(u => u.Email)
.HasMaxLength(256);
modelBuilder.Entity<MemberRole>()
.HasKey(userRole => new
{
userRole.UserId,
userRole.RoleId
})
.ToTable("MemberRole");
modelBuilder.Entity<MemberLogin>()
.HasKey(login => new
{
login.UserId,
login.ProviderKey,
login.LoginProvider
})
.ToTable("MemberLogin");
modelBuilder.Entity<MemberClaim>()
.ToTable("MemberClaim");
modelBuilder.Entity<RoleEntity>()
.ToTable("Role");
modelBuilder.Entity<RoleEntity>()
.Property(r => r.Name)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("RoleNameIndex")
{
IsUnique = true
}));
modelBuilder.Entity<RoleEntity>()
.HasMany(r => r.Users)
.WithRequired()
.HasForeignKey(ur => ur.RoleId);
#endregion
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With