12

I am following the Microsoft Architecture Guide for creating an ASP.NET Core Web Application.

The guide implements the clean architecture pattern which is pretty straight forward.

If you look at the sample project which is using the clean architecture pattern you will see that there is an Infrastructure/Identity folder that contains the ApplicationUser.cs class.

My issue:
I am using Entity Framework and one of my Business Entities in the ApplicationCore class library needs to contain a list of ApplicationUser. The ApplicationCore library shouldn't be referencing any other projects. It contains all of the Interfaces and Business Entities. How can I keep the ApplicationUser class in my Infrastructure/Identity project and still use it in one of my business entities in the ApplicationCore project without breaking the rules.

I know one solution is to not store the ApplicationUser entity in my Infrastructure project. However, I feel like it should be there since it will always rely on Identity as it implements IdentityUser.

Blake Rivell
  • 13,105
  • 31
  • 115
  • 231
  • 2
    It's in infrastructure because ApplicationUser is inheriting form IdentityUser, which is **authentication** and authentication is **infrastructure concern**. You **shouldn't ever** put authentication into your core domain, because (almost) no business in the world has `User` in ubiquitous language, process etc. When you have a shop, you have **Customers**, but no Users. Users is a technical term. A user may be related to a customer (i.e. userid and customer ID may be same or joined via a 1:1 or n:1 relation). Because a user can be deleted or blocked, but a customer remains – Tseng Dec 07 '18 at 09:02
  • Also see [this issue](https://github.com/dotnet-architecture/eShopOnContainers/issues/785#issuecomment-424708870) on GitHub for a clarification of it. You should keep in mind, that the eShopOnContainers is not just a clean architecture, but also involves topics like domain driven design and in ddd using the ubiquitous language (its that what the domain experts of the company speak, like the sales man, marketing, not the software developer) is imperative. A user, in technical terms is just a means to identify/verify a users identity and hence a customer is never same as an user – Tseng Dec 07 '18 at 09:08
  • Cause you know, you can have Customers who do not have a login, when the order is accepted via fax or phone – Tseng Dec 07 '18 at 09:08

3 Answers3

4

User is an entity and it should be in Core layer.

But you shouldn't use ApplicationUser : IdentityUser in the Core layer because it's tied up to the ASP.NET Identity. The Core layer should not know what technologies are going to implement the domain.

What if tomorrow you want to use another library for user management? That's not the Core layer's concern.

What you can do is to use an interface or base User class in the Core layer and let the Infrastructure layer be worried about the library choice decision.

Sasan
  • 3,840
  • 1
  • 21
  • 34
  • 1
    How can someone do that?? ApplicationUser is entity so it should be in the Core (I agree) but it has to extends IdentityUser cause if I don't do that so I can't use it in AspIdentityDbContext... The issue that I realized that if you are dealing with any package that has DbContext like AspCore.Identity or IdentityServer4 you will end up reference those packages in your Core cause eventually you will use their entities as part of your core entities otherwise you can't even do a migration using your core entities – Marzouk Feb 27 '20 at 15:05
0

In Clean Architecture:

Application Core Types

• Entities (business model classes that are persisted) and Aggregates

• Interfaces

• Services

• DTOs

• Specifications

• Exceptions

Infrastructure Types

• EF Core types (DbContext, Migrations)

• Data access implementation types (Repositories)

• Infrastructure-specific services (FileLogger, SmtpNotifier, etc.)

So the ApplicationUser.cs is an entity, it shouls be in Application Core

Khai Nguyen
  • 935
  • 5
  • 17
  • 1
    Microsoft does an entire manual on clean architecture and has a sample project to reference it in my links above and they throw the ApplicationUser class in the Infrastructure project. Any idea why? – Blake Rivell Dec 07 '18 at 06:10
  • Maybe is it wrong? Microsoft said that the persistent entity is in Application Core. If it is in Infrastructure, that is a business entity, isn't it? – Khai Nguyen Dec 07 '18 at 06:15
  • 1
    So there is nothing wrong with having ApplicationUser in the ApplicationCore project and installing Microsoft.AspNetCore.Identity.EntityFrameworkCore so it can inheret from IdentityUser? – Blake Rivell Dec 07 '18 at 06:23
  • 1
    I mean if you use ApplicationUser.cs as a persistent entity, you would move it into Application Core. – Khai Nguyen Dec 07 '18 at 06:34
  • 1
    In eShop sample, they place ApplicationUser.cs in Infrastructure, it is not correct, I think. Let's ask community about this – Khai Nguyen Dec 07 '18 at 06:41
  • 3
    Down voting because I don't think it answer the question. – Willian May 06 '21 at 05:56
0

This is my own problem as well and it seems opinion based somehow. I end up that if you are depending on any package that has a DbContext specified inside it, so you will reference this package in your Core project.

For example, I am using AspCore.Identity and IdentityServer4 and I have many DbContexts for that but let's say two for now:

ConfigurationDbContext and IdentityDbContext and those two contexts control two entities (just for making things easier) Client (The OAuth2 Client) and IdentityUser So now and I already have all of that as Infrastructure but now I want to have my own Core Entities ApplicationUser and ApplcationClient so how can I put those in my Core without letting them inherited their parents so I can query against them, save them or retrieve them from any source.

I don't know exactly the perfect answer for that but I end up putting those entities in the Core and reference the NuGet packages in my core which obviously not follow the clean architecture roles but I couldn't find a better solution than that.

Marzouk
  • 2,650
  • 3
  • 25
  • 56