IdentityUser Classes as Direct Customer and Reseller Customer in ASP.NET Core 3.0 - ef-code-first

I am creating a web app for a service using ASP.NET core 3.0. There are two types of users of the app
User like Admin and Reseller (Service Provider)
Customers of Reseller
I have created a class Reseller with some additional info specific to reseller
public class Reseller : BaseEntity
{
public string CompanyName { get; set; }
public virtual ApplicationUser User { get; set; } //login account of reseller
public virtual IList<ResellerCustomer> Customers { get; set; }
}
This means reseller will have a login tied to this class.
Also each reseller may have many customers and their login will be created by resellers but they will not have any additional info, however I have to make sure that I should be able to find Reseller of the logged in user and also customers of logged in reseller at any time. In future there is a possibility that there will be direct customers of the service not tied to any resellers.
So I created this class too
public class ResellerCustomer:BaseEntity
{
public virtual Reseller Provider { get; set; } // Please don't worry about name :)
public virtual ApplicationUser User { get; set; } //Login account of customer
}
I am keep the ApplicationUser class to its minimum so it serves for Reseller, Admins and Reseller Customer logins
I am unsure if I will be able to achieve what I'm trying to. I can go ahead and try this but I have a large project here and having some confidence before I get my hands dirty would be saving a lot of time .
Is this good enough? What would be the best approach.

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

.NET identity user, separation of conserns

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.

How to access users when Identity project uses EF Core and Class Library uses EF6 with same database

We have a .NET Core project that uses Identity 3 and IdentityDbContext using EF Core for user management. The generated tables are stored in a common SQL server database that is also being used by another project in our solution that is a .NET 4.5.2 Framework DataLayer using EF6.
(Just some more background - the .NET Core project is an authorization server that uses OpenIddict to implement OpenIdConnect and Oauth2 and is configured with Identity so that we can save users to the database and login and authenticate)
Once we've authenticated, we make calls to our API end point. The API talks to a DataLayer that works with EF6. From this project I need to fetch the logged in user and work with users for various queries. Ideally, I wanted to use and extend the same AspNetUsers table.
I am wondering what the recommended approach is here? If I try to generate a User DbContext in the EF6 project I have to add a new migration and the scaffolding wants to create a new table - one that already exists in the database. I am a little unsure about having 2 separate contexts in 2 different projects and how these can "play nice" together.
I have handled similar scenario recently. I followed this approach.
I have a separate Class Library for Data Layer, which has Identity related Repositories/Stores, migrations and DbContext. The DbContext takes connection string from the host project.
.Net Core project has connection string specified in appSettings.json. This connection string points to same database. This project implements IdentityServer3 and acts as Token Service.
.Net 4.5.2 project has connection string specified in web.config . This also points to same database. This app gets token from .net core project and uses that Bearer Token to access other APIs.
I created another project to keep the Entities and this project is referenced in both .net core and .net hosts.
This way i have one common data layer for 2 host projects and 2 different service/business layers for 2 host projects. It is working nicely for me.
As EF 7.0 doesn't support seeding, I have a console app for seeding data into database. Even this console app accesses the same database through Data Layer.
So 3 different projects are accessing same database.
I can't share my code with public. I hope this helps.
I was able to get this to work. The main issue is that I just wanted to access my AspNetUsers table that was generated by Identity 3 in the DotNet Core project in my DotNet 4.51 DataLayer class library project.
I achieved this by creating a User.cs Entity class in the class library EF 6 project and making sure it's properties matched the columns from the Identity 3 generated ApplicationUser.cs class.
User.cs
public class User{
[Key]
public string Id { get; set; }
public int AccessFailedCount { get; set; }
public string ConcurrencyStamp { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public bool LockoutEnabled { get; set; }
public DateTimeOffset? LockoutEnd { get; set; }
public string NormalizedEmail { get; set; }
public string NormalizedUserName { get; set; }
public virtual string PasswordHash { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public virtual string SecurityStamp { get; set; }
public bool TwoFactorEnabled { get; set; }
public string UserName { get; set; }
}
I then set up an EntityConfiguration to map to the AspNetUsers table
UserConfiguration.cs
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
ToTable("AspNetUsers");
}
}
In my DbContext class I added a DbSet for my Users entity:
public virtual IDbSet<User> Users { get; set; }
I then ran the Add-Migration command to scaffold the changes. Once generated, I commented out the code and applied the migration to the database. This generates a row in the __MigrationsHistory table for the AspNetUsers table but doesn't try to recreate the table.
I was then able to successfully talk to the AspNetUsers table from the DataLayer EF6 project :)
Also it seems that I can also extend the AspNetUsers table with custom columns now by adding properties to my User.cs class and doing the migrations in the EF6 Datalayer project.

How to design an internal Web Api using ASP.NET Web API

I am totally stuck. After searching for days, I finally decided to put my problem in front of you guys.
I need to develop a web api (using ASP.NET Web API 2) that would be used internally by a phone app and a web site. But I don't know how to design these specific cases:
1) Budget:
Budget Object:
public class Budget
{
public int Id { get; set; }
public string Name { get; set; }
public decimal TotalAmount { get; set; }
public decimal PendingAmount { get; set; }
public decimal ApprovedAmount { get; set; }
public decimal PaidAmount { get; set; }
public List<DepartmentBasicInfo> AvailableToDepartments { get; set; }
public string CurrencyCode { get; set; }
}
Budget Api controller:
public IHttpActionResult Get([FromUri]Models.BudgetModels.BudgetQueryModel query) {
return Ok(budgets);
}
The problem is all the Amount fields are calculated (not present in the database). The budgets need to return these when listed on the web page.
Then there are other web pages that would need a drop down list where it need to show budget name and currency and I do not want to calculate the budget amounts as this is a huge overhead in this case.
so the questions are:
1) As this is an internal web api, would this make sense to create two separate actions where one will return the whole Budget object and the other will return a thin Budget object (without Amounts and AvailableToDepartments properties) where calculations are not required, if yes what should be the route url?
2) Is there any clean way to able to use the same Budget class both for create and update in API because I am thnking that calculated fields do not belong to these operations.
3) Is it a good idea to pass a parameter to the Get method so it does not calculate budgets?
What is the cleanest way to handle these kind of cases? Please keep in mind that this is for an internal use api.
Thanks!
Iffi

Mapping SignalR connections to users

Consider a web application like facebook, that can send realtime notifications to users.
What is the best way, using asp.net SignalR, to keep track of which connection ids belong to which user, even if the user disconnects, or reconnects later ?
Check out the following blog post:
Mapping ASP.NET SignalR Connections to Real Application Users
Briefly, you would be adding the connection ids to user on the OnConnected method and remove that connection on the OnDisconnected method. Keep in mind that an application user can have multiple connections. So, you need to have a one to many relationship between your user and the connection ids. The above linked post explains it in details with a sample.
I did this for an internal app. The way I did it is that when a user connects, I have the server ask the user to register themselves. This way I know that not only a user is connected and their signalR connnectionID, but they can also tell me any other information (like username or whatever).
When they reconnect I ask them to do it again.
SignalR will maintain the same connectionID per client even if they reconnect which is nice. A reconnection is not the same as an initial connection. New connections indicate a new client, but a reconnection is on the same client.
In my app I maintained a seperate threadsafe dictionary that I kept track of which user and which connectionID was doing what. This way I can say "oh, send message to user ABC" and look up their connectionID. Then act on the Hub's clients object in signalR for that connectionID. If you do it this way you can even have the same "user" in mutliple connections. Imagine user "abc" is open in two browser tabs. If you went strictly by connectionID they'd be technically two different users. But, by maintaining some sort of local collection grouping users and connections you can now have multiple connections for the same user.
I should mention that if you do it this way, you should make sure your site handles what happens when it restarts and loses all the connection information. For me, when someone reconnects I ask them to again re-identify themselves. This way I can re-build my local dictionary when the server comes online without worry. It does have more overhead because now you are asking all your clients to send information to you, but depending on your user case this could be staggered or bunched or otherwise distributed to help you handle load.
In general, however you get local information (whether by asking the user to supply it), or by http context session info, you need to track it yourself.
Well I used a different approach, I extended the ApplicationUser class like that:
// 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 int ApplicationUserId { get; set; }
//public string Name { get; set; }
//public string Address { get; set; }
//public string City { get; set; }
//public string State { get; set; }
//public string Zip { get; set; }
[Required]
public string Email { get; set; }
[Required]
public override string UserName { get; set; }
[NotMapped]
public string ConnectionId { get; set; }
[NotMapped]
public string ChattingUserConnectionId { get; set; }
//public string HomeTown { get; set; }
//public DateTime? BirthDate { get; set; }
}
And in my hub i'm doing something like that:
public class ChatHub : Hub
{
#region Data Members
private static ApplicationDbContext applicationDbContext = new ApplicationDbContext();
private static UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(applicationDbContext));
private static List<ApplicationUser> connectedUsers = new List<ApplicationUser>();
And when a user connects to the chat, I get his ApplicationUser object by his user name and add it to the connectedUsers list. When he disconnects, I remove him.
I ran into some random exceptions with EF states and such which made me create the ApplicationDbContext and UserManager each time it is accessed instead of setting it in a static object:
private ApplicationUser GetCurrentUser()
{
ApplicationDbContext applicationDbContext = new ApplicationDbContext();
UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(applicationDbContext));
var userName = Context.User.Identity.GetUserName();
var user = userManager.FindByName<ApplicationUser>(userName);
return user;
}
Edit:
The hub code has some problems loading child objects of the user. This code which is also used in the asp.net template will work better, ApplicationDBContext is not needed:
private ApplicationUserManager _userManager
{
get
{
return HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
}
var user = _userManager.FindByName<ApplicationUser, string>(userName);
There's a very good article on ASP.NET's SignalR tutorial section.
I've included the introductory paragraph below.
Mapping SignalR Users to Connections
Each client connecting to a hub passes a unique connection id. You can
retrieve this value in the Context.ConnectionId property of the hub
context. If your application needs to map a user to the connection id
and persist that mapping, you can use one of the following:
The User ID Provider (SignalR 2)
In-memory storage, such as a dictionary
SignalR group for each user
Permanent, external storage, such as a database table or Azure table
storage Each of these implementations is shown in this topic. You use
the OnConnected, OnDisconnected, and OnReconnected methods of the Hub
class to track the user connection status.
UserID Provider
If you're using ASP.NET's standard membership provider (IPrincipal.Identity.Name) you can just do the following to access a client based on a user account. If you have your own user system you can create your own provider.
public class MyHub : Hub
{
public void Send(string userId, string message)
{
Clients.User(userId).send(message);
}
}

Resources