I recently updated my API to support Asp.NetCore.Identity. Therefor i had to remove a lot of fields in my User class because they already exist in the IdentityUser class, from which User inherits.
In my old User class i validated for string length and email using DataAnnotations.
[Required]
[EmailAddress]
public string Email { get; set; }
In my new class i tried overwriting the existing fields with my own and add the Annotations but this does not work.
How do you validate fields with IdentityUser?
Jakob
You have to use UserValidator
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
UserManager.UserValidator = new UserValidator<ApplicationUser>(UserManager) { };
//you can override validator or validation for specific property
}
}
Related
So I started my project using the identity scaffolding and created an application user class that inherits from identity user
using Microsoft.AspNetCore.Identity;
namespace test6.Models
{
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
and some classes that inherit from this class
using Microsoft.AspNetCore.Identity;
namespace test6.Models
{
public class Teacher : ApplicationUser
{
public string Course { get; set; }
}
}
I have set up my roles and they seem to be working fine, however my problem is that I am trying to retrieve data from users and when retrieving data that is specific to a class that has inherited from applicationuser like Course from Teacher I get an error which is because my usermanager is initialised with ApplicationUser
private readonly UserManager<ApplicationUser> _userManager;
The method I'm using to retrieve users is this
[HttpGet]
public async Task<IActionResult> ListTeacher()
{
var users = await _userManager.GetUsersInRoleAsync("Teacher");
return View(users);
}
So I have tried to initialise usermanager with Teacher to test but I get an error I think it's because in the dependancy I used ApplicationUser and I don't think you can use more than one. So my question is what possible solutions are there for this.(Sorry if my question isn't great or my explanation is poor)
Ok I think I've found a solution, turns out you can add another dependancy.
builder.Services.AddIdentityCore<Teacher>()
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<Teacher, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
With this I can initialise usermanager with Teacher and so far it has worked.
using the latest (current) RC1 of asp.net5 I'm looking at creating a simple relationship between a User entity and a WorkLog entity.
Is it possible to use the ApplicationUser Class from Identity as a starting point and use the ApplicationUser key which is defined as the linking key? I have had problems extending the ApplicationUser in the past and therefore generated a seperate dbcontext (pointing to the same database) and created my own plumbing in order to pass the IdentityUsers Id into my seperate dbcontext. Does anyone have any examples of extending the IdentityDbContext adding foreign key tables mapping to the IdentityUser Class?
Example below
//DBContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<WorkLogItem> WorkLogItems { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity<WorkLogItem>(
e =>
{
e.Property(p => p.id).IsRequired().UseSqlServerIdentityColumn();
});
}
}
//WorkLogItem
public class WorkLogItem
{
public int id { get; set;}
public String UserId { get; set; }
public int Hours { get; set; }
public String Description { get; set; }
}
//ApplicationUser
public class ApplicationUser : IdentityUser
{
public ICollection<WorkLogItem> WorkLogItems { get; set; }
}
Doing what you've asked is expected to work out of the box. You can look at this commit to see the difference between a newly created MVC 6 project with Identity and your schema above.
Registering a user, and refreshing /Home/Index causes WorkLogItems to be added as expected. Note you don't need a separate DB context for this.
public IActionResult Index()
{
var user = _db.Users.Include(p => p.WorkLogItems).FirstOrDefault();
if (user != null)
{
user.WorkLogItems.Add(new WorkLogItem { Description = "New item added" });
_db.SaveChanges();
ViewBag.WorkItems = user.WorkLogItems.ToList();
}
else ViewBag.WorkItems = new WorkLogItem[] { };
return View();
}
The key items to be aware of when you add any collection to an existing entity are;
Make sure you add the migration and update the databse
Make sure you use Include on the query because EF7 does not support Lazy Loading.
I would like to extend Application User. Here's an example:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
I tried this but it seems like when I login if any of these properties is set to a null in the database then when the /Token call is made it returns with an error.
Can someone tell me. Do I need to make a change to the way these properties are set here or in another place?
If i understand your question correctly, a simple solution to your problem could be to create a nullable type. Can you please share what you would like to do? Create a custom identity provider, for example?
I have an issue that I have been struggling with. I would appreciate any help
So, I have an application that uses Code first. For authentication, I use Asp.Net Identity 2.0.1. So I have a User class that derives from Identity User like this:
public class User: IdentityUser
{
public virtual UserInfo UserInfo { get; set; }
public virtual Organization Organization { get; set; }
}
Then i define my Context as:
public class IdentityContext: IdentityDbContext<User>
{
public IdentityContext(): base("Name=IdentityContext")
{
}
static IdentityContext()
{
Database.SetInitializer<IdentityContext>(new CreateDatabaseIfNotExists<IdentityContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new UserMap());
modelBuilder.Configurations.Add(new UserInfoMap());
}
}
Then i enable migrations using this context. And since Organization class is linked to User it also is added to the migration. But I dont want that, since its different from the Identity classes. My Organization class is as follows:
public partial class Organization: EntityBase
{
public Organization()
{
this.Users = new List<User>();
}
public int OrganizationId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public virtual ICollection<User> Users { get; set; }
}
This derives from EntityBase and not from IdentityUser class and is handled differently.
What I would be able to do is to handle all my non-identity classes through a different context, lets say AppContext that could be defined as:
public class AppContext: DbContextBase
{
public AppContext(): base("Name=IdentityContext")
{
}
static AppContext()
{
Database.SetInitializer<AppContext>(new CreateDatabaseIfNotExists<AppContext>());
}
public new IDbSet<T> Set<T>() where T : class
{
return base.Set<T>();
}
protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Configurations.Add(new OrganizationMap());
}
}
And then enable a second migration for this context.
But when I enable a second migration it fails with the exception that "Migrations have already been enabled in project 'Datastore'. To overwrite the existing migrations configuration, use the -Force parameter.". Although it still creates the Configuration file for the second migration.
So when i try to add a migration for this configuration it complains the following:
One or more validation errors were detected during model generation:
Datastore.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no
key defined. Define the key for this EntityType.
Datastore.IdentityUserRole: : EntityType 'IdentityUserRole' has no key
defined. Define the key for this EntityType.
Datastore.UserInfo: : EntityType 'UserInfo' has no key defined. Define the key for this
EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type >'IdentityUserLogin' that has no> keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type >'IdentityUserRole' that has no
keys defined.
UserInfoes: EntityType: EntitySet 'UserInfoes' is based on type 'UserInfo' that has no >keys defined.
I am not sure how to get around this? Any help is really appreciated
The idea was to inherit the AppContext with IdentityDbContext. IdentityDbContext itself inherits from DbContext so it has all the functionality available for DbContext plus extra configuration requirements for the Asp.Net Identity framework
I have a codefirst POCO, and i want to specify a LastEditUser from my current ASP.NET IDENTITY user. I tried type ApplicationUser that gets generated with the new project. but it just saves as null.
Here is my current Attempt
public class SomeClass
{
public string SomeProperty { get; set; }
public ApplicationUser LastEditMember { get; set; }
}
And here is how i try to save it in my controller.
string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
instannceOfSomeClass.LastEditMember = currentUser;
After loading this again. the LastEditMember property is null.
I would suggest using the UserManager class to get the user object instead of working with the DbContext object. You can use UserManager.FindByIdAsync(currentUserId) to get the user. Also I am considering that this code is hit only after a user logs into the application else the currentUserId will be null