CursorPool
← 返回首页
ABP Framework logo

ABP Framework

18

将 ABP 框架的规则与 MCP server 打包为 Cursor 插件,辅助 ABP 开发。

16 条规则

# ABP Core Conventions

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

## 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 |