Agent skill

abp-core

Core ABP Framework conventions - module system, DI registration, base classes (ApplicationService, DomainService), IClock, BusinessException, localization, async patterns. Use when working on any ABP project, asking about ABP fundamentals, or unsure which skill applies.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/abp-core

SKILL.md

ABP Core Conventions

Documentation: https://abp.io/docs/latest API Reference: https://abp.io/docs/api/

Key Rules

  • Use IClock / Clock.Now instead of DateTime.Now / DateTime.UtcNow
  • Use ITransientDependency / ISingletonDependency instead of AddScoped/AddTransient/AddSingleton
  • Use IRepository<T> instead of injecting DbContext directly
  • Check base class properties (Clock, CurrentUser, GuidGenerator, L) before injecting services
  • Use BusinessException with namespaced error codes for domain rule violations

Module System

Every ABP application/module has a module class that configures services:

csharp
[DependsOn(
    typeof(AbpDddDomainModule),
    typeof(AbpEntityFrameworkCoreModule)
)]
public class MyAppModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        // Service registration and configuration
    }
}

Note: Middleware configuration (OnApplicationInitialization) should only be done in the final host application, not in reusable modules.

Dependency Injection Conventions

Automatic Registration

ABP automatically registers services implementing marker interfaces:

  • ITransientDependency → Transient lifetime
  • ISingletonDependency → Singleton lifetime
  • IScopedDependency → Scoped lifetime

Classes inheriting from ApplicationService, DomainService, AbpController are also auto-registered.

Repository Usage

You can use the generic IRepository<TEntity, TKey> for simple CRUD operations. Define custom repository interfaces only when you need custom query methods:

csharp
// Simple CRUD - Generic repository is fine
public class BookAppService : ApplicationService
{
    private readonly IRepository<Book, Guid> _bookRepository; // ✅ OK for simple operations
}

// Custom queries needed - Define custom interface
public interface IBookRepository : IRepository<Book, Guid>
{
    Task<Book> FindByNameAsync(string name); // Custom query
}

public class BookAppService : ApplicationService
{
    private readonly IBookRepository _bookRepository; // ✅ Use custom when needed
}

Exposing Services

csharp
[ExposeServices(typeof(IMyService))]
public class MyService : IMyService, ITransientDependency { }

Important Base Classes

Base Class Purpose
Entity<TKey> Basic entity with ID
AggregateRoot<TKey> DDD aggregate root
DomainService Domain business logic
ApplicationService Use case orchestration
AbpController REST API controller

ABP base classes already inject commonly used services as properties. Before injecting a service, check if it's already available:

Property Available In Description
GuidGenerator All base classes Generate GUIDs
Clock All base classes Current time (use instead of DateTime)
CurrentUser All base classes Authenticated user info
CurrentTenant All base classes Multi-tenancy context
L (StringLocalizer) ApplicationService, AbpController Localization
AuthorizationService ApplicationService, AbpController Permission checks
FeatureChecker ApplicationService, AbpController Feature availability
DataFilter All base classes Data filtering (soft-delete, tenant)
UnitOfWorkManager ApplicationService, DomainService Unit of work management
LoggerFactory All base classes Create loggers
Logger All base classes Logging (auto-created)
LazyServiceProvider All base classes Lazy service resolution

Useful methods from base classes:

  • CheckPolicyAsync() - Check permission and throw if not granted
  • IsGrantedAsync() - Check permission without throwing

Async Best Practices

  • Use async all the way - never use .Result or .Wait()
  • All async methods should end with Async suffix
  • ABP automatically handles CancellationToken in most cases (e.g., from HttpContext.RequestAborted)
  • Only pass CancellationToken explicitly when implementing custom cancellation logic

Time Handling

Never use DateTime.Now or DateTime.UtcNow directly. Use ABP's IClock service:

csharp
// In classes inheriting from base classes (ApplicationService, DomainService, etc.)
public class BookAppService : ApplicationService
{
    public void DoSomething()
    {
        var now = Clock.Now; // ✅ Already available as property
    }
}

// In other services - inject IClock
public class MyService : ITransientDependency
{
    private readonly IClock _clock;

    public MyService(IClock clock) => _clock = clock;

    public void DoSomething()
    {
        var now = _clock.Now; // ✅ Correct
        // var now = DateTime.Now; // ❌ Wrong - not testable, ignores timezone settings
    }
}

Tip: Before injecting a service, check if it's already available as a property in your base classes.

Business Exceptions

Use BusinessException for domain rule violations with namespaced error codes:

csharp
throw new BusinessException("MyModule:BookNameAlreadyExists")
    .WithData("Name", bookName);

Configure localization mapping:

csharp
Configure<AbpExceptionLocalizationOptions>(options =>
{
    options.MapCodeNamespace("MyModule", typeof(MyModuleResource));
});

Localization

  • In base classes (ApplicationService, AbpController, etc.): Use L["Key"] - this is the IStringLocalizer property
  • In other services: Inject IStringLocalizer<TResource>
  • Always localize user-facing messages and exceptions

Localization file location: *.Domain.Shared/Localization/{ResourceName}/{lang}.json

json
// Example: MyProject.Domain.Shared/Localization/MyProject/en.json
{
  "culture": "en",
  "texts": {
    "Menu:Home": "Home",
    "Welcome": "Welcome",
    "BookName": "Book Name"
  }
}

❌ Never Use (ABP Anti-Patterns)

Don't Use Use Instead
Minimal APIs ABP Controllers or Auto API Controllers
MediatR Application Services
DbContext directly in App Services IRepository<T>
AddScoped/AddTransient/AddSingleton ITransientDependency, ISingletonDependency
DateTime.Now IClock / Clock.Now
Custom UnitOfWork ABP's IUnitOfWorkManager
Manual HTTP calls from UI ABP client proxies (generate-proxy)
Hardcoded role checks Permission-based authorization
Business logic in Controllers Application Services

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results