MVC 5 Code First adding new database table with UserId - c#

So right now my IdentityModels.cs looks like this:
using System;
using System.Data.Entity;
using System.Security.Claims;
using System.Security.Policy;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Leepio.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
//company
[Display(Name = "Virkshomedsnavn")]
public string CompanyName { get; set; }
public string ZipCode { get; set; }
//company
public int NrEmployees { get; set; }
//company
public string WorkField { get; set; }
public string Language { get; set; }
//Student
public string University { get; set; }
public string StudyProgramme { get; set; }
public int Semester { get; set; }
public string GraduationDate { get; set; }
//
[AllowHtml]
public string Description { get; set; }
//Student
public string Skills { get; set; }
public string Website { get; set; }
public string Address { get; set; }
//Student
[DataType("date")]
public DateTime DateOfBirth { get; set; }
public virtual ICollection<Blog> Blogs { get; set; }
public virtual ICollection<Application> Applications { get; set; }
public virtual ICollection<Project> Project { get; set; }
public virtual IList<Experience> Experience { get; set; }
public virtual ICollection<Skill> Skill { get; set; }
public virtual IList<Education> Education { get; set; }
public virtual IEnumerable<Experience> ExperienceOrdered { get { return Experience.OrderByDescending(e => e.EndYear); } }
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();
}
public System.Data.Entity.DbSet<Leepio.Models.Project> Projects { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.NewsletterMails> NewsletterMails { get; set; }
public System.Data.Entity.DbSet<Skill> Skill { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.Application> Applications { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.Contract> Contracts { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.Experience> Experience { get; set; }
public System.Data.Entity.DbSet<Leepio.Models.Blog> Blogs { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Education> Educations { get; set; }
}
}
What I want to do is, through code (migrations), add a new table as an extensions to the user table (AspNetUsers) through code as to when I register a new user with data taken from facebook, the data that I don't need for the main Users Table can go to the second one, lets say call it "FBData" with the appropriate userId.
To put it in perspective:
Register user would add userID, FirstName, LastName, Email to Users table and at the same time add ID and Locale, Gender in the FBData table.

Microsoft Identity uses AspNetUserClaims to store all additional data you specified in your ApplicationUser model class. When you use external Authentication Provider such as Facebook, Google etc. a new entry is created in AspNetUserLogins table to store the ProviderKey. This key is used when user is logging in to your application for the second time.
For my understanding your plan to create a FBData table is not necessarily good. How about you add Google Authentication after? Will you create a GData table?
The best option would be in your AccountController in ExternalLoginCallback (function triggered when the user is redirected back from your external authentication provider to your page) map what you received from facebook to your ApplicationUser and maybe redirect the the user to the registration form with pre-populated fields to finish the registration cycle. All the trash data you can store if you like in a separate table AspNetUserClaims_External but you have to model it first.
Check:
https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/4_ImplicitFlowAuthenticationWithExternal

There are a few things you need to do. First you can create a FbData class with the properties you need in that table. Then add the properties you need to the ApplicationUser Class. You need the foreign key for the FbData table
public int FbDataId { get; set; }
and you also need to add the virtual property for the table:
public virtual ICollection<FbData> FbDatas { get; set; }
Last in your IdentityContext add you DbSet for your table:
public DbSet<FbData> FbData { get; set; }
Run the application on a clean db to see your changes reflected..
You can also override the OnModelCreating class in your IdentityContext to make any modifications to the Generated Identity Tables.

Related

Creating JWT auth without using IdentityUser (and IdentityRoles) in .NET Core API 5

It's been 2-3 days that I tinker around the JWT authentication on .NET Core API without any significant success and without finding anything that suits my needs. I'm actually working to implement an API on top of an existing database. So I already have an existing user class that is done and configure using a dbContext with EF Core.
I don't want to inherit IdentityUser on this class. The reason is that an old application run on the database and it needs to be able to authenticate without passing by my API. So in short, I can't modify any fields or add any tables for compatibility reason. For example, here is my user table already containing fields named "UserMail", "Username" and "RoleId".
public class MyCustomUser {
public int UserId { get; set; }
public string Username { get; set; }
public byte[] Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserMail { get; set; }
public int RoleId { get; set; }
// [...]
}
What I don't want:
public class MyCustomUser: IdentityUser {
public int UserId { get; set; }
public string Username { get; set; } // Conflict
public byte[] Password { get; set; } // Conflict
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserMail { get; set; } // Conflict
public int RoleId { get; set; } // Issue
// What will appear in base
// ---------------------------------------------------
public virtual string UserName { get; set; }
public virtual string NormalizedUserName { get; set; }
[ProtectedPersonalData]
public virtual string Email { get; set; }
public virtual string NormalizedEmail { get; set; }
[PersonalData]
public virtual bool EmailConfirmed { get; set; }
public virtual string PasswordHash { get; set; }
}
Is there a way to add an IdentityUser with custom fields. I.E.:
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyCustomDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddIdentity<MyCustomUser, MyCustomRole>();
// [...]
}
I believe my problem is more of a lack of finding resources on the matter as all the informations to this date that I found online were all using a brand new IdentityUser.
Some resources that I looked at, without quite answering my question:
https://code-maze.com/identity-asp-net-core-project/
How to get users from a existing database for identityServer4
.Net Core API with EF Core Code First and IdentityUser

Add custom index to entity that inherits from User, which inherits from IdentityUser in EF

I'm making ASP.NET MVC Project with user identity. My User class now inherits from IdentityUser:
[Table("Users")]
public class User : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Patronymic { get; set; } // Отчество
public string Avatar { get; set; }
public DateTime? DateOfBirth { get; set; } // Дата рождения
public DateTime? RegisterDate { get; set; } // Actualy it is a dateTime :)
public bool? Sex { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User> 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;
}
}
Then I made the Doctor class, which inherits from it:
[Table("Doctors")]
public class Doctor : User
{
[Key]
public int DoctorId { get; set; }
public string CurriculumVitae { get; set; }
}
As you can see, I have added the custom index field DoctorId.
But UserManager can't create the entities
So the question is HOW CAN I ADD THE CUSTOM INT ID INDEX?
I found the solution! To force entity to create the key we need to add this:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int DoctorId { get; set; }
instead of this
[Key]
public int DoctorId { get; set; }
But this is NOT the best solution.. Theremore DON'T INHERIT FROM USER class to classes wich realize roles!

Create a relationship between USERS in writing REVIEWS

Want to create a Reviews table and got confused what foreign keys I need to place there. I want the ability of ONE user leave Reviews on the page of SECOND user. here is my current model. What do I need to add there?
REVIEWS
using System;
using System.Collections.Generic;
namespace sellwalker.Models
{
public class Review : BaseEntity
{
public int ReviewId{get;set;}
public string Content{get;set;}
public DateTime CreatedAt{get;set;}
public int UserId{get;set;}
public User Reviewer {get;set;}
}
}
USERS
using System;
using System.Collections.Generic;
namespace sellwalker.Models
{
public class User : BaseEntity
{
public int UserId{get;set;}
public string FirstName{get;set;}
public string LastName{get;set;}
public string Email{get;set;}
public string Password{get;set;}
public string Status{get;set;}
public string ProfilePic {get;set;}
public List<Order> Orders {get;set;}
public List<Product> products {get;set;}
public List<Review> Reviews {get;set;}
public User()
{
Orders = new List<Order>();
products = new List<Product>();
Reviews = new List<Review>();
}
}
}
With current table I can write reviews but I want to link it to the special user. System doesn't let me add one more UserId there so what is the best solution here?
You could go with something like that:
Review Model:
public class Review
{
public int Id { get; set; }
//...
public int ReviewerId { get; set; }
public virtual User Reviewer { get; set; }
public int ReviewedUserId { get; set; }
public virtual User ReviewedUser { get; set; }
}
User Model:
public class User
{
public int Id { get; set; }
//...
public virtual ICollection<Review> WrittenReviews { get; set; } = new HashSet<Review>();
public virtual ICollection<Review> MyReviews { get; set; } = new HashSet<Review>();
}
And then you have to specify the connections using fluent API because EF wont know wich navigation property belongs to wich.
Fluent API Code:
modelBuilder.Entity<Review>()
.HasRequired(x => x.ReviewedUser)
.WithMany(x => x.MyReviews);
modelBuilder.Entity<Review>()
.HasRequired(x => x.Reviewer)
.WithMany(x => x.WrittenReviews);

unable to add view when using model

I have the following model in my application, but when I try to generate a view on the controller using it I get the error "Unable to retrieve metadata for Jop_Offers_Website.Models.JobRequest":
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using WebApplication3.Models;
namespace Jop_Offers_Website.Models
{
public class JobRequest
{
public int Id { get; set; }
public string Message { get; set; }
public DateTime ApplyDate { get; set; }
public int JobId { get; set; }
public string UserId { get; set; }
public virtual Jobs job { get; set; }
public virtual ApplicationUser user { get; set; }
}
}
When I use other models to add view, or if I comment out the job and user properties the view is generated successfully.
The Jobs Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Jop_Offers_Website.Models
{
public class Jobs
{
//id to be primary key of Jobs table
public int Id { get; set; }
//job title
[Required]
[Display (Name ="أسم الوظيفة")]
public string JobTitle { get; set; }
//job description
[Required]
[Display(Name ="وصف الوظيفة ")]
public string JobDescription { get; set; }
//jop image
[Display(Name ="صورة الوظيفة ")]
public string JobImage { get; set; }
//id of categories to relate to Job category Type 1 to many relationship
//[Required]
public int CategoryId { get; set; }
//object of category to detect job category
public virtual categories category { get; set; }
}
}
The ApplicationUser model:
using System.Data.Entity;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
namespace WebApplication3.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit https://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
public string UserType { get; set; }
public string Neabouring { 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("JobConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
public System.Data.Entity.DbSet<Jop_Offers_Website.Models.categories> categories { get; set; }
public System.Data.Entity.DbSet<Jop_Offers_Website.Models.Jobs> Jobs { get; set; }
public System.Data.Entity.DbSet<Jop_Offers_Website.Models.RoleViewModel> RoleViewModels { get; set; }
public System.Data.Entity.DbSet<Jop_Offers_Website.Models.JobRequest> JobRequests { get; set; }
}
}
Any model used to add views but I can't add the view by using JobRequest Model
and when I use JobRequest model without ApplicationDbContext the view is generated successfully .

Many to Many self Join with Entity Framework Code First

Consider this Poco:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Fullname { get; set; }
}
Now i want to implement a follow technique where a user may follow other users so basically its self Many to Many relationship
problem is i don't know how exactly i can achieve this in Entity Framework Code-First ?
I thought of a linker Table :
public class UserFollow
{
public int Id { get; set; }
public int Follower { get; set; }
public int Following { get; set; }
public DateTime FollowDate { get; set; }
}
i want to be able to get All Followers and Following from every User Object?
This is quite simple using EF code-first as you only need the User POCO:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Fullname { get; set; }
public ICollection<User> FollowedUsers { get; set; }
}
The collection means that a User is related to other users.
PS: I noted you added a timestamp in your solution example. To achieve that you should still add the collection changing the generic type to whatever suits your needs.
Hope it helps.

Categories

Resources