I'm trying to go through this tutorial on the External Authentication Services (C#). I need some initial explanations to go forward. Looking inside the default template that ships MVC5, I see this:
// You can add profile data for the user ...
public class ApplicationUser : IdentityUser
{
public string HomeTown { get; set; }
public DateTime? BirthDate { get; set; }
}
What if I want to call it User instead of ApplicationUser? Maybe I want to add a navigation properties so I can establish relationship with my other models? Also when I look at the table, the name is AspNetUsers instead of ApplicationUser. Finally, What if I want to use my own context?
Thanks for helping.
1)What if I want to call it User instead of ApplicationUser?
You can change to any names you want, just make sure to replace ApplicationUser with the name.
2)Maybe I want to add a navigation properties so I can establish
relationship with my other models?
If you have a class call Address, you want to add addressId as a foreign key, see below:
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
}
public class User : IdentityUser
{
public string HomeTown { get; set; }
public DateTime? BirthDate { get; set; }
public int AddressId { get; set; }
[ForeignKey("AddressId")]
public virtual Address Address { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<User>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<Address> Addresses { get; set; }
}
3)Also when I look at the table, the name is AspNetUsers instead of
ApplicationUser.
ASP.NET Identity is inherited from the The ASP.NET membership system. When you register a new user
using the default template, AspNetUsers and AspNetUserRoles etc.. these tables are created by default.
You can modify these table name by modifying the IdentityModel.cs. For more detail take a look at the following link:
How can I change the table names when using Visual Studio 2013 ASP.NET Identity?
4)What if I want to use my own context?
You can create your own DBContex, MVC 5 allow you to have mutiple DBContext, such as ApplicationDbContext and DataDbContext(custom DbContext).
ApplicationDbContext usually contains ASP.NET Membership data table.
DataDbContext usually contains data tables unrelated to users.
public class Blog
{
public int BlogId { get; set; }
public int Title { get; set; }
}
public class MyDbContext : DbContext
{
public MyDbContext()
: base("DefaultConnection")
{
}
public DbSet<Blog> Blogs { get; set; }
}
Note: You may need to use EF Migrations, see details here :
ASP.Net Identity customizing UserProfile
Related
My current aim is to build a database structure using classes in Entity Framework & ASP MVC.
I currently have a Users table and a Posts table. What I would like to do is create a many to many relationship for Users who have liked Posts (whilst conserving who created the post). And be able to access for each user all of the posts they have liked. Currently I have these classes but I'm unsure of how to link them as all of the online examples are linking Primary Keys from different databases where I just want to use the Username Parameter. Any help would be great. I have this so far.
public class Posts
{
[Key]
public virtual int PostId { get; set; }
public virtual string Title { get; set; }
public virtual string URL { get; set; }
[DisplayName("Main Text")]
public virtual string TextBody { get; set; }
public int PostLikes { get; set; }
private DateTime Datedata = DateTime.Now;
public DateTime PostDate { get { return Datedata; } set { Datedata = value; } }
public virtual Users User { get; set; }
public ICollection<PostLikes> UsersWhoHaveSigned { get; set; }
}
{
public class Users
{
[Key]
public virtual int UserId { get; set; }
public virtual string Username { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual List<Posts> Post { get; set; }
}
}
I have not built the UsersWhoHaveSigned table yet. Early experimentation caused me so much backtracing it was painful. Any help would be great.
Edit: I was hoping to ask for help and then appropriate that informtaion to fit my example which utilises the individual accounts add-on. This produces some addition files that are now causing interference with the code you've provided.
Here is the IdentityModels.cs file.
using System.Data.Entity;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
namespace Coursework2.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 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();
}
}
}
I believe that the assembly directives at the top are preventing system.data.entity from being used so when I try to implement ApplicationDbContext : DbContext I get error messages :/
Ideally I'm looking to use the IdentityModels.cs file as a replacement for the users class. But still very lost.
First of all, I recommend that you use the singular form for your class names, as EF will automatically pluralize table names.
Second, for a key property, you can just use the term Id, without any annotations, and EF will pick it up as the principal key.
Finally, I'll assume you are looking to use a Code-First approach. Consider the following classes (yours, but refactored for clarity purpose):
public class Post
{
public virtual Guid Id { get; set; }
public virtual string UserName { get; set; }
public virtual User User { get; set; }
public virtual ICollection<PostLike> Likes { get; set; }
}
public class PostLike
{
public virtual Guid Id { get; set; }
public virtual Guid PostId { get; set; }
public virtual Post Post { get; set; }
public virtual string UserName { get; set; }
public virtual User User { get; set; }
}
public class User
{
public virtual Guid Id { get; set; }
public virtual string UserName { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public virtual ICollection<PostLike> Likes { get; set; }
}
To make it work, you'd need a DbContext such as the following. Pay attention to the OnModelCreating method, which is where the magic happens:
public class ApplicationDbContext
: DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<PostLike> PostLikes { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>()
.HasAlternateKey(u => u.UserName);
modelBuilder.Entity<User>()
.HasMany(u => u.Posts)
.WithOne(p => p.User);
modelBuilder.Entity<Post>()
.HasOne(p => p.User)
.WithMany(u => u.Posts)
.HasForeignKey(p => p.UserName)
.HasPrincipalKey(u => u.UserName);
modelBuilder.Entity<Post>()
.HasMany(p => p.Likes)
.WithOne(pl => pl.Post);
modelBuilder.Entity<PostLike>()
.HasOne(pl => pl.Post)
.WithMany(p => p.Likes);
modelBuilder.Entity<PostLike>()
.HasOne(pl => pl.User)
.WithMany(u => u.Likes)
.HasForeignKey(pl => pl.UserName)
.HasPrincipalKey(u => u.UserName);
}
}
Voila! I hope it answers your question ;)
If so, please don't forget to mark my post as the answer!
Edit:
I'll provide some explanations, that I had left out to answer your question ASAP.
So, first thing you need to do, is to declare the UserName as an alternate key, because you want to create relationships depending on it, and you already have the 'Id' principal key declared.
Second, on each object that should own a User reference base on the UserName alternate key, you need to declare the object's UserName property as the foreign key of the relationship, and the User's UserName property as the principal key.
In other words, the foreign key is the property that a referencing object uses for the relationship, and the principal key is the property based on which the referenced object is bound to the referencing one.
Note that principal keys must have a key or alternate key constraint, or it won't work.
Just to comment on your answer. I found that I had to use
using Microsoft.EntityFrameworkCore and remove System.Data.Entity - This was causing the program to be confused as to which DbContext I wanted to use. Thanks!
I am developing my first project in ASP.NET MVC and I want to improve, what I already done. I have web application with identity authorization,
so every user can login using his own credentials.
I have done event/applicationuser model, controller a views, so I can display, modify or delete events as well as users.
What I want to do is, that every user should have option to choose one or more events and sign up for selected event. As well as user should be able to see all his events after successful log in.
So I have to create new model for communicate between user and event. The problem is, that user inherits by IdentityDbContext and event by DbContext. Does anyone know some simple way to solve my problem?
This is my code:
1, ApplicationUser
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
2, Event model
public class Event
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime? EventDate { get; set; }
public string EventLocation { get; set; }
public string Description { get; set; }
}
3, Event context
public class Context:DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
public DbSet<Event> Event { get; set; }
4, Model EventParticipant to communicate between user and event - not working
public class EventParticipant
{
public int ID { get; set; }
public string ApplicationUserID { get; set; }
public bool Status { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public virtual ICollection<Event> Event { get; set; }
}
the Identity has ApplicationDbContext class for identity context.
i go to the ApplicationDbContext class and set it partial and create one class with same name and set it partial.
I write my configuration of context in my class
and create my migration without any Problems.
My Application is all fine and within IdentityModels I set each class (table). But I want to show in my Razor View the UserName from AspNetUsers and not the GUID. I currently store the GUID but thats all i'm able to display in the views
I'm thinking there must be a built in easy way to do this - and that I don't need to do any mapping or do i
I'm using EF6 and MVC4.5
Here is my class :
public partial class x23BatchImport
{
public int x23BatchImportId { get; set; }
public Nullable<DateTime> DateTimeFromFilename { get; set; }
public string UserId { get; set; }
public string Filename { get; set; }
public decimal? Length { get; set; }
public Nullable<DateTime> StartDateTime { get; set; }
public Nullable<DateTime> StopDateTime { get; set; }
//public virtual ApplicationUser ApplicationUser { get; set; }
}
...here is an extract from IdentityModels.cs
namespace AscendancyCF.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 class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
//public System.Data.Entity.DbSet<AscendancyCF.Models.ApplicationUser> ApplicationUser { get; set; }
public System.Data.Entity.DbSet<AscendancyCF.Models.SupplyPointType> SupplyPointTypes { get; set; } ETC ETC
.....NB all my tables are declared here then I use OnModelCreating to set up relationships some of the time...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Reference : http://blogs.msdn.com/b/adonet/archive/2010/12/06/ef-feature-ctp5-fluent-api-samples.aspx
base.OnModelCreating(modelBuilder);
// Configure the 1-1
modelBuilder.Entity<SupplyPoint>()
.HasOptional(a => a.SupplyPointAddress)
.WithMany()
.HasForeignKey(u => u.SupplyPointAddressId);
}
Entity Framework has a set of model and property naming conventions that it uses by default. Currently, it's not able to figure out that UserId is a foreign key to an ApplicationUser.
If you don't want to add any manual mappings, you have to change your naming. The simplest would be to rename the ApplicationUser property to User.
public virtual ApplicationUser User { get; set; }
When doing your queries, use Include() to eager load the User property with the matching ApplicationUser...
// using System.Data.Entity; // add this using to use Include()
var context = new ApplicationDbContext();
var batchImport = context.x23BatchImport
.Include(x => x.User)
.(x => x.x23BatchImportId == 1)
.Single();
var username = batchImport.User.UserName;
Your other alternatives are:
Change UserID property to ApplicationUserId
Specify the foreign key in a manual mapping in OnModelCreating()
Specify the foreign key on the model using data annotations
In my project I use MVC4 and some external database using Entity as orm.
I decided to use membership given by MVC, so I just changed in default ConnectionString to point to my external db.
Then, when I launch the app first time, few tables were added, so far so good. Now, the problem is , that when I map new created userProfile table into my dataContext model, then I have a conflict, because this table allready exists in accountModel.
Account model and my new generated model are in the same namespace, which I don't wanna change, so what can I do?
here is class generate by ADO entity model using view add tables method:
public partial class UserProfile
{
public UserProfile()
{
this.Predictions = new HashSet<Prediction>();
}
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<Prediction> Predictions { get; set; }
}
and here from membership
[Table("UserProfile")]
public partial class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
both exist in the same name space, and are in conflict.
You can remove the auto generated class and create a partial class to extend the AccountModel UserProfile class instead.
Create a partial class with the same name and same namespace:
public partial class UserProfile
{
public UserProfile()
{
this.Predictions = new HashSet<Prediction>();
}
public virtual ICollection<Prediction> Predictions { get; set; }
}
By doing this, you have the Predictions property into the membership UserProfile class.
i'd like to know, I have a application in asp.net mvc and nhibernate. I've read about that in the Views on asp.net mvc, shouldn't know about the Domain, and it need use a DTO object. So, I'm trying to do this, I found the AutoMapper component and I don't know the correct way to do my DTOS, for some domain objects. I have a domain class like this:
public class Entity
{
public virtual int Id { get; set; }
public virtual bool Active { get; set; }
}
public class Category : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Category() { }
}
public class Product : Entity
{
public virtual string Name { get; set; }
public virtual string Details { get; set; }
public virtual decimal Prince { get; set; }
public virtual int Stock { get; set; }
public virtual Category Category { get; set; }
public virtual Supplier Supplier { get; set; }
public Product() { }
}
public class Supplier : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Supplier() { }
}
I'd like to get some example of how can I do my DTOs to View ? Need I use only strings in DTO ? And my controllers, it should get a domain object or a DTO and transform it on a domain to save in repository ?
Thanks a lot!
Cheers
There is no guidelines on this matter and it depends on your personal chice. I have few advices that have proven useful in practice:
1. Use flat DTOs - this means that the properties of the DTO must be as primitive as possible. This saves you the need for null reference checking.
For example if you have a domain object like this:
public class Employee
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop Employee Boss{get; set;}
...
}
And you need to output in a grid a list of employees and display information for their 1st level boss I prefer to create a DTO
public class EmployeeDTO
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop bool HaveABoss{get;set}
prop string BossFirstName{get; set;}
prop string BossLastName{get; set;}
...
}
or something like this (-:
2. Do not convert everything to sting - this will bind the DTO to a concrete view because you'll apply special formatting. It's not a problem to apply simple formatting directly in the view.
3. Use DTOs in your post actions and than convert them to domain objects. Usually controller's actions are the first line of deffence against incorrect data and you cannot expect to be able to allways construct a valid domain object out of the user's input. In most cases you have to do some post-processing like validation, setting default values and so on. After that you can create your DTOs.