Open Closed

ABP Suite generates entities as public instead of internal (DDD best practice) #10115


User avatar
0
juan.acedo created

Hello, I would like to report an issue with ABP Suite regarding the access modifier used when generating entities. Current Behavior: When creating entities through ABP Suite, they are generated with the public access modifier by default. Expected Behavior: According to DDD (Domain-Driven Design) best practices and ABP's own recommendations in the documentation, entities should be generated as internal to properly encapsulate the domain layer and prevent direct access from outside the domain. Suggestion: ABP Suite should generate entities with the internal access modifier by default, following the framework's own DDD guidelines. Additional Context: This aligns with the principle of keeping domain entities encapsulated within their bounded context and only exposing them through the application layer when necessary. Thank you for your attention to this matter.


1 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    1. Solution
    • Current status and recommendation:

      • ABP entities are commonly defined as public in templates and tools because EF Core, mapping, design-time tooling, and cross-layer usage frequently require public visibility. The official docs and templates do not mandate internal for entities, and many framework base classes (e.g., AuditedEntity) are public.
      • Where stricter encapsulation is desired, you can still keep the domain model internal to the domain layer and expose only DTOs via the application layer. However, making entity classes internal can break EF Core proxies, design-time tools, or cross-assembly usage unless you configure internals visibility.
    • Practical options you can apply today:

      1. Keep entities public and encapsulate behavior via aggregates, domain services, and factories. Do not expose entities from the application layer; expose DTOs only.
      2. If you insist on internal domain entities:
        • Place your DbContext and entities in the same domain (or domain EFCore) assembly so EF Core can access the types.
        • If your DbContext is in another assembly, add InternalsVisibleTo for the consuming assembly (and optionally for EF Core proxies):
    // In your Domain project (AssemblyInfo.cs or at top of a .cs file)
           using System.Runtime.CompilerServices;
    
           [assembly: InternalsVisibleTo("YourProjectName.EntityFrameworkCore")]
           [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // if using dynamic proxies (e.g., for mocking)
    
     - Avoid exposing entities across layers. Continue to expose DTOs in the Application layer and map using ObjectMapper in the same assembly that can see internals.
    
    • About ABP Suite default generation:

      • Suite generates public entities by default. If you want internal, change the access modifier after generation or customize your Suite template to emit internal for entity classes.
      • Be aware that switching to internal may require InternalsVisibleTo as shown above and co-locating DbContext and entity types.
    • Related ABP guidance you can leverage:

      • If you need custom entity key patterns or to avoid the conventional Id property and still use repositories and CRUD app services, prefer AbstractKeyCrudAppService over CrudAppService when your entity doesn’t use the default Id pattern:
    public class MyAppService :
            AbstractKeyCrudAppService<
                MyEntity,        // entity
                MyEntityDto,     // dto
                MyKeyType,       // key type
                PagedAndSortedResultRequestDto,
                MyCreateUpdateDto
            >, IMyAppService
        {
            public MyAppService(IRepository<MyEntity, MyKeyType> repo) : base(repo) { }
        }
    
    For entities without the conventional Id property, override GetKeys() in your entity:
    
    public class MyEntity : AuditedEntity
        {
            public Guid MyEntityId { get; set; }
    
            public override object[] GetKeys() => new object[] { MyEntityId };
        }
    
    1. Sources
    • https://abp.io/docs/latest/framework/architecture/modularity/basics
    • https://abp.io/docs/latest/framework/architecture/domain-driven-design
    • https://abp.io/docs/latest/framework/architecture/best-practices
    • https://abp.io/support/questions/2649
    • https://github.com/abpframework/abp

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.1.0-preview. Updated on November 17, 2025, 08:31
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.