I'm starting with the base architecture of a monolithic project, I'm trying to implement a generic DbContext within a layered architecture, specifically within the Common project, which will be the reference in all the other layers.
My problem is given by the use of AspNet Identity, where the DbContext must Inherit from IdentityDbContext and pass an argument of type ApplicationUser or TUser.
The issue is that my ApplicationUser class is inside the Domain project, which contains all the classes that represent my database model.
I don't want my Common project to have the reference of some other project, because it assumes that this would be a generic project for general use.
How is the best way to solve this architecture?
enter image description here
I try to have a BaseUserEntity base class inside the Common project and have this be my TUser that needs IdentityDbContext, but it gets complicated when I have to generate the configuration of the database tables...
I have a model where I will implement several types of users.
UserA
UserB
And that all these inherit from my ApplicationUser, due to the inconvenience that I have, it could not move forward with the development.
Related
I would like to know if someone can assist me with this little dilemma...
I am following a clean architecture project setup using .net core 3.1. With projects:
API
Domain
Infrastructure
Application
In Domain I do not reference any projects (or package) everything else references from it.
And I have the table below in Domain:
Company Table
I have added my identity to the Infrastructure later in which I have have a ApplicationUser which extends IdentityUser.
So the scenario is as follows:
user signs up and later gets attached to a company. A company can have many users (this being AspNetUser)
So when a user signs in he is attached to that company and can do certain actions under that company
And when I retrieve the company it will have a list of users thats attached to it.
So the question I have is, what do I do so that I can have a Company with a collection of users, also without having to add a reference From Domain to infrastructure
Common pattern to resolve this issue is to define an abstraction of your user class or an interface in the domain layer. This abstraction is used in the company class and the user implementation in infrastructure project derives from it.
If inheritance is not an option you can go for an interface in domain project and have an adapter in infrastructure project wrapping the actual user implementation providing access to its properties.
EDIT: I should probably add that in my project (which was based on the ASP.NET Core 2.1 - WebApp with MVC, with "Individual User Accounts), I don't have "AppUser" (or an equivalent class that inherits from IdentityUser), and ApplicationDbContext inherits from IdentityDbContext - not from IdentityDbContext (or IdentityDbContext).
I'm currently learning / starting with ASP.NET Core and use "Add New Scaffolding Item" to Add Custom user data to Identity and noticed that I cannot use the existing context (ApplicationDbContext) if I want the scaffolder to create my custom user class. The only way to have that field enabled is if I add a new context, which will also add a new connection string. But the new context seems to be essentially doing the same that my already existing context does.
I also noticed that the two new classes (AppExtendedContext and AppExtendedUser in my case) were put under Areas/Identity/Data, while I'd actually expect them to be under Data and Models.
So I was wondering: Why? ;-)
Or, to put it in more actionable terms: Would it be safe to refactor the generated code back to only use a single ApplicationDbContext? What would I be losing / what kind of trouble would I get myself into?
The answer could be as simple as "for pragmatic reasons" (e.g. because it makes the automatic code generation easier / safer); and in that case, moving these things around should be fairly safe as long as I'm not going to use the scaffolder again. But then again, it might make life more difficult/confusing when upgrading (e.g. to ASP.NET Core 2.2, or ASP.NET Core 3.0).
Just trash your AppExtendedContext and AppExtendedUser classes and use the ApplicationDbContext and AppUser and add your customizations there.
They are ready for modification (they inherit from IdentityDbContext<TUser> and IdentityUser<TKey> respectively. Feel free to rename them to something more familiar to your application (such as Customer or CustomerUser), if you don't like the AppUser name.
There's really no need to inherit from AppUser or ApplicationDbContext, they are the final/concrete classes for your Core Identity.
Make sure your context inherits from IdentityDbContext<>. You have to specify the type to use for your application user, which you can just create as a class that extends IdentityUser (given the fact you want to start extending the IdentityUser class). Go for something like YourCustomContextType : IdentityDbContext<YourCustomUserType>.
As for the Identity services registration you need to specify your class there too using AddDefaultIdentity<YourCustomUserType>().AddEntityFrameworkStores<YourCustomContextType>().
Make sure you also look at how other people approach extending the Identity functionality:
How to extend available properties of User.Identity
Why is the IdentityUser class in the Microsoft.AspNet.Identity.EntityFramework package instead of being included in the Microsoft.AspNet.Identity.Core package?
Why should it depend on EntityFramework? It seems to be a simple class.
What am I missing?
I typically separate by Data layer from my DAL. Adding a dependency to EntityFramework for the IdentityUser class seems a bit much.
The design of the core of Identity is not coupled to EF or to any specific shape of user and role types. Everything is abstracted by the stores. In fact, for any given persistence provider, the types don't even need to be POCOs at all!
For Identity 3.0 we considered having our current types in core (in fact, at some point we had them there) but we got pretty solid feedback from people familiar with other persistence frameworks that although those types can comply to a common definition of "POCO", they are very EF specific.
We also considered having base classes in core that we would extend for EF in the EF package. We landed where we are because there didn't seem to be enough benefit in this. It was between adding the complexity of an extra layer of inheritance (more complexity would make it easier for us to introduce bugs) vs. the fact that the types themselves aren't that complex and that persistence provider writers who want to take them as a starting point are welcome to copy & paste the code.
You asked:
Why is the IdentityUser class in the
Microsoft.AspNet.Identity.EntityFramework package...Why should it
depend on EntityFramework?
This is because the out-of-the-box implementation for Identity actually depends on Entity Framework.
The ASP.NET site has the following article:
Overview of Custom Storage Providers for ASP.NET Identity which indicates:
By default, the ASP.NET Identity system stores user information in a
SQL Server database, and uses Entity Framework Code First to create
the database. For many applications, this approach works well.
However, you may prefer to use a different type of persistence
mechanism, such as Azure Table Storage, or you may already have
database tables with a very different structure than the default
implementation. In either case, you can write a customized provider
for your storage mechanism and plug that provider into your
application.
The same page also should answer your question in the comments about creating a custom implementation of IUser:
Customize the user class
When implementing your own storage provider, you must create a user
class which is equivalent to the IdentityUser class in the
Microsoft.ASP.NET.Identity.EntityFramework namespace:
I'm trying to implement Identity 2.0 in my ASP.NET MVC 5 solution that abides the onion architecture.
I have an ApplicationUser in my core.
namespace Core.DomainModel
{
public class ApplicationUser {...}
}
In my Data Access Layer I'm using Entity Framework 6.1 and my context derives from IdentityDbContext and herein lies the problem. ApplicationUser needs to derive from Microsoft.AspNet.Identity.EntityFramework.IdentityUser
namespace Infrastructure.DAL
{
public class TestContext : IdentityDbContext<ApplicationUser> {...}
}
My domain model shouldn't reference Microsoft.AspNet.Identity.EntityFramework that would go against the idea of the onion.
What's a good solution?
Yep, this is the big problem with the Identity framework which I have found no good solution yet.
I contemplated adding EF to my domain project, but decided against it in one project: domain models are not aware about ApplicationUser, only using Id for the current user which they get from
ClaimsPrincipal.Current.Claims
.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)
.Value
In that project I kept all Identity code in Web and Data projects.
In my other project I have added Identity and EF all over the place, including Domain project. And guess what? nothing bad happened.
I also have looked on solutions like already provided link to Imran Baloch' blog. It looked like a lot of work to me to gain no customer value.
Just to repeat myself, there is no good solution to separate EF from Identity without rewriting a pile of code (don't like it). So either add EF to your Domain project (don't like it) or keep your Identity code in Web/Data project (sometimes not possible, so I also don't like it).
Sorry to say, but this is a low-level limitation of .Net.
You can inherit IUser from the Core namespace and the usermanager will be happy. You will need to replace the IUserStore with your own implementation. Then initializer the user manager something like:
new UserManager<ApplicationUser>(new YourNameSpace.UserStore<YourApplicationUser>()))
The problem is that you are trying to use the Onion pattern. In its foundations that you will always build dependencies.
Thrive for single responsibility of your models you are creating. You can do easily this by trying to follow Domain Driven Design properly by implementing individual models per layer:
BusinessLogic.Models.ApplicationUser
Presentiation.Models.ApplicationUser
DAL.Models.ApplicationUser
Note that all of those models are different classes even if they have 100% same properties (although it is never 100%). The drawback is that you may need to map from one model to another, but if you are trully aim for clean, modular and extensible architecture - that is the way.
Hint you can use Automapper (or ExpressMapper) to avoid code needed for mapping.
I'm new to ASP.NET MVC and I've been developing a MVC 5 application with individual user authentication. I've been doing a layered pattern when doing my applications like separating Model layer, DAL layer, Repos, etc. etc. but now in MVC 5, I want to be able to use the user and role management and authentication which they call Identity, and then still have that layered structure to my application because right now it seems Identity is pretty much coupled with the MVC project itself with the user and role models in there and the context too.
What I did in my application for now is I have all my supposed-to-be-separate layers like my DAL, UnitOfWork, Repos, other models, etc in the MVC project (in separate folders!) just to make it work, for now. And I know it's just not the right way to do it.
So can anyone point me to some good examples or articles about this or explain it directly if it's possible or not and how? Google hasn't been friendly to me about this one. Thanks!
Here is a quick draft of what I'd try...I would create these layers:
Contoso.Core (Class Library)
Contoso.Data (Class Library)
Contoso.Service (Class Library)
Contoso.Web.Framework (Class Library)
Contoso.Web (ASP.NET MVC 5.0)
Contoso.Core:
This layer holds all my entities/classes representing my database TABLES.
So for example, I would have a:
User.cs class.
Product.cs class
ProductDetail.cs class
Etc..
Some people call these entities/classes: the Domain Objects, others call it the POCO classes.
Either or, these entities/classes are defined in the Core Layer since they may (or may not) be used amongst the other layers.
Contoso.Data:
This layer is where I define my ContosoDbContext.cs class. It is inside that file that I have all my DbSet<> defined.
So for example, I would have the following inside my ContosoDbContext.cs:
public DbSet User { get; set; }
public DbSet Product { get; set; }
public DbSet ProductDetail { get; set; }
Needless to say, the Contoso.Data layer WILL HAVE A DEPENDECY on the Contoso.Core layer.
In addition, it is inside that Contoso.Data layer that I would have my Generic Repository and anything related to "data access".
Contoso.Service:
This layer would be where I place all my business rules. For example, I may have a UserService.cs class that could have a Login() method. The Login() method would receive a username/password and call the Repository to lookup the user.
Because the Service layer needs the Repository, I WILL HAVE A DEPENDENCY on the Contoso.Data layer AND because I'll be playing around with the User class (which happens to live inside the Contoso.Core layer), I WILL ALSO HAVE A DEPENDENCY on the Contoso.Core layer.
Contoso.Web.Framework:
This layer would have a dependency on the Contoso.Core, Contoso.Data and Contoso.Service.
I would use this Contoso.Web.Framework layer to configure my Dependency Injection.
Contoso.Web:
The final layer, the MVC 5.0 application, would have a dependency on the Contoso.Web.Framework AND on the Contoso.Service AND on the Contoso.Core layers.
The Controllers, would invoke methods living inside the classes defined in your Contoso.Service layer (for example the Login() method).
The Login() method may or may not, for example, return a User class (null or populated) and because it returns a User class AND BECAUSE we are inside a Controller, our Contoso.Web layer needs a dependency on the Contoso.Service and Contoso.Core.
Of course, I haven't detailed everything here or every layer but this is just to give you an example of the type of architecture I’d use.
So far, I haven't answered your question but with little I know about MVC 5.0 and its new Identity mechanism, I believe the Contoso.Core layer would need to have a dependency on Microsoft.AspNet.Identity.EntityFramework in addition to the Microsoft.AspNet.Identity.Core
Likewise, my ContosoDbContext.cs class would need to implement the IdentityDbContext interface which happens to belong to the Microsoft.AspNet.Identity.EntityFramework.dll.
This means my Contoso.Data layer would have a dependency on Microsoft.AspNet.Identity.EntityFramework and most probably the Microsoft.AspNet.Identity.Core as well...
As you say, when you create a new MVC 5.0 project, all of this exist and is defined within the single application. Nothing is or has been decoupled into layers. So in the above architecture the ContosoDbcontext.cs class lives inside the Contoso.Data layer and NOT directly inside the ASP.NET MVC application.
Since I haven't tried the new ASP.NET Identity nor have I tried to decouple things around, I wouldn't know how to honestly answer your question. I guess you'll have to try and move things around.
If and when you do, feel free to tell us how it went and what are the things/problems you encountered.
Meanwhile, I hope this has helped you shed some light (or not).
Vince