.NET identity user, separation of conserns - asp.net

I am trying to use .NET identity.
My user has properties which are related to auth. For example, email address, password, projects user has access to, etc.
Also, the user has other fields, for example favourite color.
Because color is not related to authentication, I don't want to add color as a property of ApplicationUser : IdentityUser {}.
But somehow I need to write values into that field, so I could write a repository, which takes the regular User object. But in that case I need to write the repository, hash the password myself, so what's the point having .NET Identity?
A third solution would be to make 2 tables, one for the ApplicationUser, and one for the related properties, but we already have a database, and I don't want to change everything.
One more idea what I could think of is to have ApplicationUser : IdentityUser {} as basibally a copy of User (I can't inherit from user and IdentityUser too, and can't chain it, because of database first) and have a separate AuthenticationUser : IdentityUser in the auth. context.
How sould I do it?
thanks

I think for this issue you have to change your model like:
public class Person
{
public string Color { get; set: }
public int RoleId { get; set: }
public Role Role { get; set: }
public ICollection<UserAuthentication> UserAuthentications { get; set: }
}
public class UserAuthentication
{
public Person Person { get; set: }
public int PersonId { get; set: }
}
With these models you don't have this problem.
If you have any data, you can displace that using TSql.

Related

ASP.NET tables and identity tables containing duplicate data

I am using .NET Framework 4.6.1 and Entity Framework 6.0.0.0.
I am working on an ASP.NET web application (Web API). When I see my database created by Entity Framework, the tables shown below like ASP.NET User & Application Users which have some duplicate data. Also, in IdentityUserRoles and ASPNETUserRoles also having duplicate data.
I don't want to keep these duplicate tables mainly want to continue with ASP.NET tables not identity tables. How can I achieve this, and what do I need to do? Why did these duplicate tables with the same data get created?
Below is User Model I am using :-
public class User
{
[Key]
public int id { get; set; }
public string application_user_id { get; set; }
[ForeignKey("application_user_id")]
public virtual ApplicationUser applicationuser { get; set; }
public DateTime? start_date { get; set; }
public DateTime? end_date { get; set; }
public virtual ICollection<Test> Tests{ get; set; }
}
I think the answer to your question is to inherete the properties of the identity table in your tables.
To make it clear you just need to change your model into something like this:
public class user : IdentityUser
{
...
}
this way the columns in identity user will be added to the user table, in addition to your personnalized columns of the user table, I'm not sure if I made my answer clear enough but I will put here a link if you want to learn more about how to personnalize the identity tables : Custom Identity model

Using Backlink feature of realm-dotnet in Xamarin.Forms App

My current employer is developing a mobile app using Xamarin.Forms and Asp.net mvc on the backend. I suggested to use realm in the mobile app. My manager want to see a POC(Proof of concept) app using realm with backlink feature before allowing it to be used in the app. I am working on the POC on GitHub . The documentation is very limiting and the GitHub repo of realm-dotnet don’t have good sample.
I completed the project. But unable to implement backlink. The sample app I have developed allow user to create assignees(employees) in the first page. The user can delete or edit the employees using context menu. When the user clicks on the employee name the app navigates to the ToDoListPage of that particular employee. Here the user can create ToDoItems. On this ToDoList page I want to show the ToDoItems that where assigned to that employee only.
The models were as follows:
public class Assignee : RealmObject
{
public Assignee()
{
ToDoItems = Enumerable.Empty<ToDoItem>().AsQueryable();
}
[PrimaryKey]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Name { get; set; }
public string Role { get; set; }
[Backlink(nameof(ToDoItem.Employee))]
public IQueryable<ToDoItem> ToDoItems { get; }
}
public class ToDoItem : RealmObject
{
[PrimaryKey]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Name { get; set; }
public string Description { get; set; }
public bool Done { get; set; }
public Assignee Employee { get; set; }
}
I am adding employee to each ToDo Item:
Item.Employee = Employee;
_realm.Add(Item);
Now I want to access the ToDoItems for the Employee:
Items = _realm.All<Assignee>().Where(x => x.Id == EmployeeId).FirstOrDefault().ToDoItems;
But this does not work. I will be grateful if someone can help me out by preferably writing code in my sample app or write the correct code in the reply.
Thank you
Firstly, Realm .NET doesn't currently support traversing properties (x.Employee.Id). Due to this, when I start the app and try to go to the ToDoListPage, the app crashes with the exception:
The left-hand side of the Equal operator must be a direct access to a persisted property in Realm
Realm supports object comparison, so we can fix this like so:
var employee = _realm.Find<Assignee>(EmployeeId);
Items = _realm.All<ToDoItem>().Where(x => x.Employee == employee);
Secondly, everything seemed fine in your code, so I dug a bit deeper and saw why it isn't working. The issue is that when we try to get all items with the code above, the EmployeeId parameter is null. Since the EmployeeId is being populated after the load logic has been triggered, we don't need to load the data in the ctor. So you can remove this code.
Finally, since you won't be loading the data in the ctor, and instead in the SetValues method, the UI needs to know, when the data has been updated, what exactly to redraw. Thus, you need to mark the collection to be Reactive too:
[Reactive]
public IEnumerable<ToDoItem> Items { get; set; }
Then, you need to change the SetValues method to use object comparison, instead of traversing:
async Task SetValues()
{
Employee = _realm.Find<Assignee>(EmployeeId);
Title = Employee.Name;
Items = _realm.All<ToDoItem>().Where(x => x.Employee == Employee);
}
To sum up - you don't need to try and load the data in the ctor, since you don't know when the EmployeeId will be set. You are already tracking when the property will change and inside the SetValues command you simply need to change the expression predicate.

How do you add a new user and claim in a single transaction using ASP.NET Core 2.1 Identity?

I am trying to add a new user and some other associated entities including a claim as one transaction. My classes are basically defined as below. Note that I am using int primary keys on my User class and that it is an identity column (value is provided by the database on insertion).
public class User : IdentityUser<int>
{
// custom props here
}
public class UserClaim : IdentityUserClaim<int>
{
// i actually haven't added anything to this class, it's mainly here so
// i don't have to keep specifying the user's primary key type
}
public class OtherEntity
{
public int UserId { get; set; }
[ForeignKey(nameof(UserId))]
public User User { get; set; }
// other stuff
}
I then want to add the user etc. to the database something like this:
User user = new User(){ /* set props */ };
OtherEntity other = new OtherEntity()
{
User = user
};
UserClaim claim = new UserClaim()
{
/* this is where the problem is */
UserId = user.Id,
ClaimType = "my-claim-type",
ClaimValue = "my-claim-value"
};
context.AddRange(user, other, claim);
context.SaveChanges();
I can easily link the User to the OtherEntity because I have set up the navigation property so I can just add the User to it and entity framework takes care of the filling in the UserId column. I cannot do this with UserClaim because it doesn't have the navigation property. I could call context.SaveChanges() after adding the User and entity framework would get the User.Id created by the database for me which I could use to set UserId on the UserClaim, but that would mean two transactions.
I have tried adding the navigation property to my definition of UserClaim as follows:
public class UserClaim : IdentityUserClaim<int>
{
[ForeignKey(nameof(UserId))]
public User User { get; set; }
}
But I get following runtime error:
InvalidOperationException: The relationship from 'UserClaim.User' to 'User' with foreign key properties {'UserId' : int} cannot target the primary key {'Id' : int} because it is not compatible. Configure a principal key or a set of compatible foreign key properties for this relationship.
Is there a way of creating both the user, and the claim in the same transaction?
My question should have been: "How do I add navigation properties between ASP.NET Identity classes?"
If I had looked for the answer to that I would have found the microsoft docs explaining how to do it!
The docs linked above tell you how to add the User.UserClaims navigation property:
public class User : IdentityUser<int>
{
public virtual ICollection<UserClaim> Claims { get; set; }
}
public class DataContext : IdentityDbContext</* Identity classes */>
{
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<User>(e =>
{
e.HasMany(u => u.Claims)
.WithOne()
.HasForeignKey(c => c.UserId)
.IsRequired();
});
}
}
But it doesn't show how to make the reverse UserClaim.User navigation property. I worked out that this can be done like this:
public class UserClaim : IdentityUserClaim<int>
{
public virtual User User { get; set; }
}
public class DataContext : IdentityDbContext</* Identity classes */>
{
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<User>(e =>
{
e.HasMany(u => u.Claims)
.WithOne(c => c.User) // <- this line is different
.HasForeignKey(c => c.UserId)
.IsRequired();
});
}
}
You can then create a new user and claim at the same time as per my question:
User user = new User(){ /* set props */ };
UserClaim claim = new UserClaim()
{
User = user, // <- this is the bit you can't do without the nav. property
ClaimType = "my-claim-type",
ClaimValue = "my-claim-value"
};
context.AddRange(user, claim);
context.SaveChanges();
I guess it's common sense, though I didn't realise until I inspected the actual SQL hitting the database, but this will still require two trips to the database even though we are only calling .SaveChanges() once! Entity Framework will first save the User and get the ID for the inserted row which it will then use when inserting the UserClaim.
Inserting related data is documented in Entity Framework: https://learn.microsoft.com/pl-pl/ef/core/saving/related-data
And it is also well described in other topics, for example: Entity Framework Foreign Key Inserts with Auto-Id
Every of you entites need to be set correctly for relations (foreign keys) in your entites models (without them, EF don't know what to do) and when you are adding it, you need to start from beginning, so UserClaim must be set from your User entity, for example
var user = new User(){
//properites
OtherEntity = new OtherEntity()
{
Id = 0, /*will be set automatically*/
UserId = 0 /*will be set automatically*/
/* other properites */
};
Claim = new UserClaim(){
Id = 0, /*will be set automatically*/
UserId = 0 /*will be set automatically*/
/* other properites */
}
}
ontext.Add(user);
context.SaveChanges();
You didn't provide all the information about your relations, I've just assumed this from your code.
PS. AddRange has only one parameter.
EDIT:
To clarify my answer, for everything to work, AddRange/Add need to be called with your base entity and relations inside, in tree manner.
But first you need to configure your models, something like that.
public class User : IdentityUser<int>
{
[ForeignKey("UserClaimId")]
public virtual UserClaim Claim {get;set;}
}
public class UserClaim : IdentityUserClaim<int>
{
[ForeignKey("UserId")]
public virtual User User {get;set;}
}
public class OtherEntity
{
public int UserId { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
// other stuff
}
You can also use OnModelCreating to set up entites, as described in documentation: https://learn.microsoft.com/en-us/ef/core/modeling/relationships
Entity Framework right now don't know anything about relations in Database, data types etc.
Updated code example
Edit, don't have enough reputation to add comment to your answer
Well, EF still needs to track entities. I would need to write and run some examples to check if there is some way to improve trips to database. Maybe someone could tell you more about mechanism that is behind adding related-data and if there is a way to improve it.
There are some libraries that helps with improving performance of saving changes to database, for example: https://entityframework-extensions.net
You could try it.

Implement Tag database

Well hi everyone I'm kinda new on Asp.net Mvc, and need some help to improve, in my project that I'm working at, I need to register a user and in the register the user must choose some tags that are categories related to the subject of my website, the thing is that i have a database that looks like this
Tag
public int TagId{get;set;}
public string TagName{get;set;}
public string TagColor{get;set;}
TagUser
public int TagUserId{get;set;}
public int UserId{get;set;}
I read that EF constructs the tables when there is a many to many relationship, it construct the middle table automatically so in my case do i just need to have the first model and my user model? or should i use the 2 models above plus the user model, with the second approach i don't know how to relate de data i can define the TagUserId as primary key and UserId as foreignkey and relate the tables, but do i need this? or can i do that with the first approach if someone can give me a tip i appreciate a lot. :)
Ps: Sorry for my bad English
You can keep a Tags property of type IList<Tag> in your User class and a Users property in your Tag class of type IList<User>. Entity Framework will create a third table to store the many to many association between Tag and User.
public class Tag
{
public int Id {set;get;}
public string TagName {set;get;}
public virtual IList<User> Users { get; set; }
}
public class User
{
public int Id {set;get;}
public string UserName {set;get;}
public virtual IList<Tag> Tags { get; set; }
}

Edit model with virtual field

I have a Shop model which contains several fields. One of which is a virtual User one. Whenever I try to edit one entry I get an error saying that User field is required.
public class Shop
{
//..
public virtual ApplicationUser User { get; set; }
//..
}
My workaround is this:
shop.User = shop.User; //re-set the value
shop.Active = true;
db.Entry(restaurant).State = EntityState.Modified;
db.SaveChanges();
And I have to do this for all the fields. Is this the standard approach for this or is there a better way?
Change your model to this:
public class Shop
{
//..
public int UserId {get; set; }
public virtual ApplicationUser User { get; set; }
//..
}
Entity Framework will automatically detect that UserId is the foreign key for object User. You had this problem because User is virtual (lazy loaded). When changing the model without accessing or setting this property EF thinks it's empty (I assume). The foreign key UserId is not virtual, and will be fetched together with the other properties of model Shop, so you don't have to re-set the value when saving the model.
To set a new user, you now have to do for example:
myShop.UserId = 1; // instead of setting myShop.User
For more information, see this article: http://msdn.microsoft.com/en-us/data/jj713564.aspx

Resources