My dbContext return null, when I want get list of user, which are from identity - asp.net

My dbContext return null, when I want get list of user in Index View. This list are from my database AspNetUsers table, which has been generate by identity. I can get other my database table list.
There is my ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductBrand> ProductBrands { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Address> Address { get; set; }
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Order_detail> Order_Details { get; set; }
}
There is my UserController
[Area("Admin")]
public class UserController : Controller
{
UserManager<IdentityUser> _userManager;
private ApplicationDbContext _db;
public UserController(UserManager<IdentityUser> userManager, ApplicationDbContext db)
{
_userManager = userManager;
_db = db;
}
public IActionResult Index()
{
return View(_db.ApplicationUsers.ToList());
}
}
There is my ApplicationUser.Model, which inherit IdendityUser
public class ApplicationUser : IdentityUser
{
public string Name { get; set; }
public string Surname { get; set; }
public ICollection<Recipe> Products { get; set; }
public ICollection<Order> Orders { get; set; }
}

I don't know how you register ApplicationDbContext and Identity framework on your ASP.NET Core MVC application because you didn't show them on the question.
There are couple problems in your code.
First, if you have a custom IdentityUser, like the ApplicationUser you have, you would have to use the generic version of IdentityDbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
...
}
You would need to use the matching generic version of IdentityDbContext if you have any of following:
Custom IdentityUser
Custom IdentityRole
Custom primary key
All 7 classes, user and role, plus IdentityUserRole, IdentityUserClaim, IdentityRoleClaim, IdentityUserLogin, and IdentityUserToken
After you register your custom class with IdentityDbContext, you don't need to put the class as one of the DbSet<> there:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
...
public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductBrand> ProductBrands { get; set; }
public DbSet<Product> Products { get; set; }
// public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Address> Address { get; set; }
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Order_detail> Order_Details { get; set; }
}
You would also need to use the generic version of AddIdentity<TUser>, AddDefaultIdentity<TUser>, or AddIdentityCore<TUser> in your Startup.cs, depending on what you need:
AddDefaultIdentity = AddIdentity + AddDefaultTokens + AddDefaultUI
You didn't specify what version of ASP.NET Core Identity you're using so I don't exactly know which one you use, but the following is how I registered it:
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.User.RequireUniqueEmail = ...;
...
})
.AddEntityFrameworkStores<ApplicationDbContext>();
I have all 7 classes customized as well as change the primary key from string to Guid.
Lastly, to use the dependency injected UserManager and SignInManager, you would need to correct generic version of them as well:
[Area("Admin")]
public class UserController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public UserController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public IActionResult Index()
{
// Get the user list
var users = _userManager.Users.ToList();
// Build your view model to define what your UI only needs, not just passing
// everything to it
var vm = new UserManagementListViewModel
{
Users = users.Select(x => new UserViewModel
{
UserId = x.Id,
UserSurname = x.Surname,
ProductCount = x.Products.Count(),
OrderCount = x.Orders.Count()
})
};
return View(vm);
}
}

Related

.NET querying Aspnetusers instead of Custom AuthUser and Yet AspNetUser does not Exist

I write a custom IdentityUser which is AuthUser.
public class AuthUser : IdentityUser
{
public int StudentsId { get; set; }
public virtual Students StudentProfile { get; set; }
public int InstructorId { get; set; }
public virtual Instructor InstructorProfile { get; set; }
public bool IsStudent { get; set; }
public bool IsInstructor { get; set; }
}
The context is okay as you can see
public class LmsContext : IdentityDbContext<AuthUser> //DbContext
{
}
The startup.cs is all setup
services.AddDbContext<LmsContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("UCIPrimarySchool"))
);
services.AddDefaultIdentity<AuthUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<LmsContext>();
services.AddControllersWithViews();
services.AddRazorPages();
But when I try to login I get the following error.
An unhandled exception occurred while processing the request.
SqlException: Invalid object name 'AspNetUsers'.
Microsoft.Data.SqlClient.SqlCommand+<>c.<ExecuteDbDataReaderAsync>b__169_0(Task<SqlDataReader> result)
Why is is not querying the extended AuthUser but instead goes for the none existing table AspNetUsers?
First, you should clarify your relationship and then migrations and updated the database correctly.
Change your AuthUser like this:
public class AuthUser : IdentityUser
{
public virtual Students StudentProfile { get; set; }
public virtual Instructor InstructorProfile { get; set; }
public bool IsStudent { get; set; }
public bool IsInstructor { get; set; }
}
In your Context:
public DbSet<Students> Students { get; set; }
public DbSet<Instructor> Instructor { get; set; }
Migration and update:
After successfully updating the database, you need to change your View/Shared/_LoginPartial code:
#inject SignInManager<IdentityUser> SignInManager
#inject UserManager<IdentityUser> UserManager
to
#inject SignInManager<AuthUser> SignInManager
#inject UserManager<AuthUser> UserManager
Then
Select your LmsContext Add
Then start your app,and login.

Getting computed column filled in EF Core on every call to entity

I am using code first with Entity Framework in my ASP.NET Core application. I am using a generic repository for crud operations.
I have a base audit class which is inherited by all entities in my dbcontext.
public class Audit_base
{
public int AddedUserId { get; set; }
public int ModifiedUserId { get; set; }
// I'd like to have it filled every time I query
[NotMapped]
public String AddedUsername { get; set; }
[NotMapped]
public String EditedUserName { get; set; }
}
And I have a User class in the dbcontext
public class UserMaster
{
public int Id { get; set; }
public int FullName { get; set; }
}
All my tables (about 70) inherit from the Audit_base class.
public class Book : Audit_base
{
public int Id { get; set; }
public String BookName { get; set; }
public virtual UserMaster CreatedByUser { get; set; }
public virtual UserMaster ModifiedByUser { get; set; }
}
And this is the part of generic repository class where I query these tables
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected readonly ApplicationContext _context;
public GenericRepository(ApplicationContext context)
{
_context = context;
}
public IEnumerable<T> Find(Expression<Func<T, bool>> expression)
{
return _context.Set<T>().Where(expression);
}
public IEnumerable<T> GetAll()
{
return _context.Set<T>().ToList();
}
public T GetById(int id)
{
return _context.Set<T>().Find(id);
}
}
Is there a way that I can get the user name corresponding to the created and modified userid when I query it, like a computed column?

AspNetRoles table not showing custom fields

I have recently extended my AspNetRoles table like this:
public class AspNetRoles:IdentityRole
{
public AspNetRoles() : base() { }
public String Label { get; set; }
public String ApplicationId { get; set; }
public AspNetApplications Application { get; set; }
public static readonly String SystemAdministrator = "SystemAdministrator";
}
It works fine when I create a new role. However, when I try to extract it to a list like this:
var data = dbContext.Roles.ToList();
And try to do a search like this:
data = data.Where(u => u.Id.ToString().ToLower().Contains(Input.Search.ToLower())).ToList();
I can't access the ApplicationId column. Am I missing something?
EDIT:
My dbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, AspNetRoles<string>, string>
{
public virtual DbSet<AspNetUsersExtendedDetails> AspNetUsersExtendedDetails { get; set; }
public virtual DbSet<AspNetApplications> AspNetApplications { get; set; }
public virtual DbSet<AspNetEventLogs> AspNetEventLogs { get; set; }
public virtual DbSet<AspNetRoles> AspNetRoles { get; set; }
public ApplicationDbContext() : base("AppStudio")
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I have updated my dbContext but now it shows this error: 'IdentityDbContext<ApplicationUser, AspNetRoles<string>, string>' does not contain a constructor that takes 2 arguments
You need to tell ASP.Net Identity about the custom role table that you want to use.
Edit: since the default IdentityRole implementation uses a string as the PK, the type can be omitted. Just checking futher on ASP.Net Identity version 2, as soon as you specify a custom IdentityRole class, the class declaration needs to include all types.
That means you need to declare your ApplictionDbContext like this:
public class ApplicationDbContext: IdentityDbContext<ApplicationUser, AspNetRoles, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
{
public ApplicationDbContext() : base("AppStudio")
{
//note: before this change, if you included the
//throwIfV1Schema parameter in the constructor,
//it needs to be removed.
}
//implementation
}
Note that this assumes that the Primary Key of the users table is a string. If this is not the case, substitute with the applicable type (e.g. a Guid).
You have to add AspNetRoles to your IdentityDbContext.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, AspNetRoles, string>
{
public virtual DbSet<AspNetUsersExtendedDetails> AspNetUsersExtendedDetails { get; set; }
public virtual DbSet<AspNetApplications> AspNetApplications { get; set; }
public virtual DbSet<AspNetEventLogs> AspNetEventLogs { get; set; }
public ApplicationDbContext() : base("AppStudio", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}

Many to many relationship with ASP.NET AspNetUser table gets ignored

One user can be a member of many projects while a project can have multiple members.
ASP.NET Identity ApplicationUser
public class ApplicationUser : IdentityUser
{
[Display(Name = "Projekt")]
public virtual ICollection<Project> Projects { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
My Project:
[Table("Projects")]
public class Project : IValidatableObject
{
[Key]
public int ID { get; set; }
[Required, StringLength(128), Display(Name = "Projektname"), Index(IsUnique = true)]
public string Name { get; set; }
// working one-to-many relation
[Display(Name = "Projektleiter")]
public string LeaderID { get; set; }
[ForeignKey("LeaderID"), Display(Name = "Projektleiter")]
public virtual ApplicationUser ApplicationUser { get; set; }
// many-to-many relation gets ignored
[Display(Name = "Mitarbeiter")]
public virtual ICollection<ApplicationUser> ApplicationUsers { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return new List<ValidationResult>();
}
}
No Many-to-Many table is created. The whole relation gets ignored. But the LeaderID thing is working ...
Can somebody tell me what I am missing here? (I googled the hell out of it, I deleted the whole database multiple times, I tried everything I found, no luck ...)
I would keep the ApplicationUser entity separated from whatever logic you have with the project and create another entity called Person.
public class Person
{
//Constuctor : always intantiate lists in ctor
public Person()
{
Projects = new List<Project>();
}
public int Id { get; set; }
public string IdentityId { get; set; } //gets guid from AppUser table
public ApplicationUser Identity { get; set; } // navigation property
public List<Project> Projects { get; set; }
//public int ProjectId {get; set;}//-----optional
}
so in projects know we do the same thing:
[Table("Projects")]
public class Project : IValidatableObject
{
//Constuctor : always intantiate lists in ctor
public Project()
{
Persons = new List<Person>();
}
[Key]
public int ID { get; set; }
[Required, StringLength(128), Display(Name = "Projektname"), Index(IsUnique = true)]
public string Name { get; set; }
public string PersonId { get; set; } //nav property
public List<Persons> Persons { get; set; }
public Person Person { get; set; } //context will be aware that this is fk
[Display(Name = "Projektleiter")]
public string LeaderID { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return new List<ValidationResult>();
}
}
add db sets for both entities in the dbcontext class.
Now you want to get a person with a list of projects and vice versa. For that we use the include:
var x = myContext.Persons.Include(x => x.Projects);
var d = x.ToList();
//you can use the applicationUser entity instead of person but bad things happen as the project grows.

Add list of models to Asp.net Identity

I want to assign a list of stores to a particular client, based on the Identity Model in MVC 5. I want to be able to register a user/client using the default registration in the MVC 5 example code and be able to add a store, then assign the store to the user.
I'm having trouble being able to create a working viewmodel that incorporates the idenity model with a new list.
Here is what I have so far:
Model:
public class ApplicationUser : IdentityUser
{
//[Required]
[Display(Name = "Client/Company Name")]
public string ClientName { get; set; }
public List<Store> Stores { 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;
}
}
I tried to add to the existing default dbcontext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<Store> Stores { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
My controller blows up when I try to set my store clientname to the user clientname. Clientname or any other property is unavailable for ApplicationUser.
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Stores
public ActionResult Index(ClientStoreViewModel viewModel)
{
var clients = from s in db.Stores
join c in db.Users
on s.ClientName equals u.ClientName
select new ClientStoreViewModel() { Stores = s, Users = u };
return View(clients);
}
Store class:
public class Store
{
public int Id { get; set; }
//public int ClientId { get; set; }
[Display(Name = "Client Name")]
public string ClientName { get; set; }
[Display(Name = "Store Name")]
public string Brand { get; set; }
[Display(Name = "Store Number")]
public string StoreNumber { get; set; }
[Display(Name="Store Login URL")]
public string LoginURL { get; set; }
}
Finally my viewmodel:
public class ClientStoreViewModel
{
public ApplicationUser Users { get; set; }
public Store Stores { get; set; }
public ClientStoreViewModel()
{
Stores = new Store();
Users = new ApplicationUser();
}
}

Resources