AIExtension Data Layer Overview
App Studio has zero direct database access — no DbContext, no repositories, no SQL. Every read and write goes through IAppStudioService, implemented in AIExtension.Service. This service layer is the authoritative contract for all App Studio data operations and enforces multi-tenancy, caching, and audit logging automatically.
The Architecture Principle
// What App Studio controllers do NOT have:
// ❌ AppDbContext
// ❌ IRepository
// ❌ Raw SQL queries
// ❌ Direct table access
// What App Studio controllers DO have:
// ✅ IAppStudioService (injected via DI)
// Every data operation:
public class AppController : ControllerBase
{
private readonly IAppStudioService _appService;
public AppController(IAppStudioService appService)
{
_appService = appService;
}
[HttpGet("{appId}")]
public async Task GetApp(string appId)
{
var app = await _appService.GetAppAsync(TenantId, appId);
return Ok(app);
}
}
Why This Design
The service layer always scopes queries to the requesting tenant. It is impossible for an App Studio controller to accidentally read another tenant's data because the service enforces tenantId on every operation.
App definitions are cached in Redis by the service layer. Controllers receive cached data without knowing or caring about cache state. Cache invalidation happens automatically on write operations.
Every write operation through the service layer creates an audit log entry — who changed what, when, from which IP. Controllers do not need to implement audit logic themselves.
Adding new data operations means adding a method to IAppStudioService and implementing it in AIExtension.Service — the controller is the only consumer and sees the interface, not the implementation.
Service Layer Stack
// Request flow for a read operation:
App Studio Controller
→ IAppStudioService.GetAppAsync(tenantId, appId)
→ [Cache check] Redis cache hit? return cached result
→ [Cache miss] AIExtension.Service queries AIExtension DB tables
→ Multi-tenancy filter applied (tenantId scoped)
→ Result cached in Redis with TTL
→ AppDefinition returned to controller
→ Controller returns to client
In This Guide
Why No Direct Database Access
The design rationale and what the service layer enforces.
AIExtension.Service API
Key methods: GetApp, SaveApp, GetWidgets, SaveLayout.
App Config Storage
AIExtension tables that store app definitions.
Widget Data Storage
How widget placements and overrides are persisted.
Extending the Service Layer
Adding a new data operation end-to-end.
Service Layer Caching
Redis caching strategy and cache invalidation.
Audit Trail
How every change is automatically audit-logged.