Architecture Overview
Architecture Overview
Application created with Flexbase - Architecture & Best Practices
๐๏ธ Solution Overview
The Application created with Flexbase is a modern, enterprise-grade .NET 9 application built using Clean Architecture principles with Domain-Driven Design (DDD) patterns. It leverages the Sumeru.Flex framework to provide a robust, scalable foundation for business applications.
๐ Table of Contents
๐๏ธ Architecture Overview
High-Level Architecture
graph TB
subgraph "Presentation Layer"
WebAPI[Web API Endpoints]
Controllers[Controllers]
CronJobs[Background Jobs]
end
subgraph "Application Layer"
Handlers[Command Handlers]
Queries[Query Handlers]
Services[Application Services]
DTOs[Data Transfer Objects]
end
subgraph "Domain Layer"
Models[Domain Models]
Events[Domain Events]
Rules[Business Rules]
end
subgraph "Infrastructure Layer"
Database[(Database)]
MessageBus[Message Bus]
ExternalAPIs[External APIs]
end
subgraph "Framework Layer"
FlexCore[Sumeru.Flex Core]
Bridges[Framework Bridges]
end
WebAPI --> Controllers
Controllers --> Handlers
Controllers --> Queries
Handlers --> Models
Queries --> Models
Handlers --> MessageBus
MessageBus --> Database
FlexCore --> Bridges
Bridges --> Handlers
Bridges --> Queries
Key Architectural Principles
Separation of Concerns: Clear boundaries between layers
Dependency Inversion: High-level modules don't depend on low-level modules
Single Responsibility: Each component has one reason to change
Open/Closed Principle: Open for extension, closed for modification
Interface Segregation: Clients depend only on interfaces they use
๐ Solution Structure
Project Organization
YourApplication_blank_sol/
โโโ YourApplication.Application/ # Application Layer
โ โโโ ControlContracts/ # API Contracts & DTOs
โ โ โโโ YourApplication.DTOs/ # Data Transfer Objects
โ โ โโโ YourApplication.Messages/ # Message Contracts
โ โ โโโ YourApplication.SharedEvents/ # Shared Domain Events
โ โโโ ControlHub/ # API Controllers & Jobs
โ โ โโโ YourApplication.WebControllers/
โ โ โโโ YourApplication.CronJobs/
โ โโโ Domain/ # Domain Layer
โ โ โโโ YourApplication.CommonLib/ # Common Utilities
โ โ โโโ YourApplication.DomainModels/ # Domain Entities
โ โ โโโ YourApplication.Mappers/ # Object Mapping
โ โโโ DomainHandler/ # CQRS Implementation
โ โ โโโ YourApplication.Handlers/ # Command Handlers
โ โ โโโ YourApplication.Queries/ # Query Handlers
โ โ โโโ YourApplication.PreBus/ # Message Preprocessing
โ โ โโโ YourApplication.RESTClients/ # External API Clients
โ โโโ EndPoints/ # Application Hosts
โ โ โโโ YourApplication.EndPoint.WebAPI/
โ โ โโโ YourApplication.EndPoint.Handlers.Default/
โ โ โโโ YourApplication.EndPoint.Subscribers.Default/
โ โ โโโ YourApplication.EndPoint.CronJob/
โ โ โโโ DbMigrations/ # Database Migrations
โ โโโ Infrastructure/ # Infrastructure Layer
โ โโโ Bus/ # Message Bus (NServiceBus)
โ โโโ Db/ # Database Implementations
โโโ YourApplication.Framework/ # Framework Layer
โโโ Bridge/ # Framework Bridges
โโโ PostBus/ # Message Bus Interfaces
๐ฏ Core Architectural Patterns
1. Clean Architecture
The solution follows Clean Architecture principles with clear layer separation:
Domain Layer: Contains business logic and entities
Application Layer: Contains use cases and application services
Infrastructure Layer: Contains external concerns (database, messaging)
Presentation Layer: Contains controllers and API endpoints
2. CQRS (Command Query Responsibility Segregation)
// Command Pattern
public abstract class FlexCommandBridge : FlexCommand, IFlexCommandBridge
{
// Command implementation
}
// Query Pattern
public abstract class FlexQueryBridge : FlexQuery, IFlexQueryBridge
{
// Query implementation
}
Benefits:
Clear separation between read and write operations
Independent scaling of read/write workloads
Optimized data models for each operation type
3. Domain-Driven Design (DDD)
Domain Models: Rich business entities with behavior
Value Objects: Immutable objects representing concepts
Domain Events: Business events that occur in the domain
Aggregates: Consistency boundaries for domain objects
4. Event-Driven Architecture
public abstract class FlexEventBridge : FlexEvent, IFlexEventBridge
{
// Event implementation
}
Features:
Loose coupling between components
Asynchronous processing
Event sourcing capabilities
Eventual consistency
5. Vertical Slice Architecture (Partial Implementation)
The solution demonstrates elements of Vertical Slice Architecture by organizing functionality around business capabilities rather than technical layers:
Identified Vertical Slices
graph TB
subgraph "Business Capabilities (Vertical Slices)"
subgraph "Web API Slice"
WebAPI[Web API Endpoint]
WebControllers[Web Controllers]
WebDTOs[API DTOs]
end
subgraph "Command Processing Slice"
Handlers[Command Handlers]
HandlerEndPoint[Handler Endpoint]
HandlerMessages[Command Messages]
end
subgraph "Query Processing Slice"
Queries[Query Handlers]
QueryDTOs[Query DTOs]
QueryMappers[Query Mappers]
end
subgraph "Event Processing Slice"
Subscribers[Event Subscribers]
SubscriberEndPoint[Subscriber Endpoint]
SharedEvents[Shared Events]
end
subgraph "Background Processing Slice"
CronJobs[Background Jobs]
CronJobEndPoint[Cron Job Endpoint]
JobSchedules[Job Schedules]
end
subgraph "External Integration Slice"
RESTClients[External API Clients]
RetryPolicies[Retry Policies]
ExternalDTOs[External DTOs]
end
end
WebAPI --> WebControllers
Handlers --> HandlerEndPoint
Queries --> QueryDTOs
Subscribers --> SubscriberEndPoint
CronJobs --> CronJobEndPoint
RESTClients --> ExternalDTOs
Vertical Slice Characteristics
1. Feature-Based Organization
Each slice represents a complete business capability
Contains all layers needed for that capability
Minimal coupling between slices
2. Self-Contained Slices
// Example: Web API Slice
YourApplication.WebControllers/ # Presentation
โโโ Controllers/ # API Controllers
โโโ DTOs/ # API Contracts
// Example: Command Processing Slice
YourApplication.Handlers/ # Application Logic
โโโ CommandHandlers/ # Business Logic
โโโ Messages/ # Command Contracts
// Example: External Integration Slice
YourApplication.RESTClients/ # Infrastructure
โโโ ExternalAPIs/ # External Services
โโโ RetryPolicies/ # Resilience Patterns
3. Independent Deployment
Each endpoint can be deployed independently
Separate scaling for different capabilities
Technology-agnostic slice boundaries
4. Shared Infrastructure
Common framework bridges
Shared domain models
Centralized configuration
Benefits of Vertical Slice Architecture
Business Alignment: Code organization matches business capabilities
Team Autonomy: Teams can work on slices independently
Reduced Coupling: Changes in one slice don't affect others
Easier Testing: Each slice can be tested in isolation
Independent Scaling: Scale slices based on business needs
๐ ๏ธ Technology Stack
Core Technologies
Runtime
.NET
9.0
Application runtime
Framework
Sumeru.Flex
9.0.0
Core framework
ORM
Entity Framework Core
Latest
Data access
Messaging
NServiceBus
Latest
Message bus
Mapping
AutoMapper
13.0.1
Object mapping
Logging
Serilog
Latest
Structured logging
Validation
FluentValidation
Latest
Input validation
Database Support
SQL Server - Primary database
MySQL - Alternative database
PostgreSQL - Alternative database
Multi-tenant - Separate database per tenant
Message Bus Options
RabbitMQ - Open-source message broker
Azure Service Bus - Cloud messaging service
SQL Server - Database-based messaging
Learning Transport - Development/testing
โ
Best Practices Implemented
1. Configuration Management
Multi-Source Configuration Strategy
public class AutoConfigurationProvider : IHostConfigurationProvider
{
public void Configure(IConfigurationBuilder configBuilder, HostBuilderContext context, string? userSecretName = null)
{
configBuilder
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
if (!string.IsNullOrEmpty(userSecretName) && context.HostingEnvironment.IsDevelopment())
{
configBuilder.AddUserSecrets(userSecretName);
}
// Azure Key Vault integration
var keyVaultName = tempConfig["Azure:KeyVaultName"];
if (!string.IsNullOrEmpty(keyVaultName))
{
var keyVaultUri = new Uri($"https://{keyVaultName}.vault.azure.net/");
configBuilder.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());
}
}
}
Configuration Priority (Highest to Lowest):
Command Line Arguments
Azure Key Vault
User Secrets (Development only)
Environment Variables
appsettings.{Environment}.json
appsettings.json
2. Dependency Injection
Service Registration Pattern
public static class DbEndPointConfig
{
public static void AddFlexBaseDbServices(this IServiceCollection services)
{
// Single Tenant Configuration
EnableSingleTenant(services);
// Multi Tenant Configuration (commented)
//EnableMultitenant(services);
}
private static void EnableSingleTenant(IServiceCollection services)
{
ConfigureSingleTenantDb(services);
ConfigureFlexDb.ForRepositoryForSqlServer(services);
}
}
3. Error Handling
Custom Exception Types
public class BadRequestException : Exception
{
public BadRequestException(string message) : base(message) { }
}
public class InternalServerErrorException : Exception
{
public InternalServerErrorException(string message) : base(message) { }
}
4. Logging Strategy
Structured Logging with Serilog
Correlation IDs for request tracing
Environment-specific log levels
Centralized logging configuration
5. Database Patterns
Repository Pattern with Unit of Work
// Single Tenant
services.AddTransient<IWriteDbConnectionProviderBridge, AppSettingsWriteDbConnectionProvider>();
services.AddTransient<IReadDbConnectionProviderBridge, AppSettingsReadDbConnectionProvider>();
// Multi Tenant Support
ConfigureFlexDb.ForMultitenantMasterDbForSqlServer(services);
ConfigureFlexDb.ForRepositoryForSqlServer(services);
6. Object Mapping
AutoMapper Configuration
public class CoreMapperConfiguration : FlexMapperProfile
{
public CoreMapperConfiguration() : base()
{
#region Input
//CreateMap<YourAPIModel, YourDomainModel>();
#endregion
#region Output
//CreateMap<YourDomainModel, YourOutputAPIModel>();
#endregion
}
}
โ๏ธ Configuration Management
Environment-Specific Configuration
The solution supports multiple environments with specific configuration files:
appsettings.json
- Base configurationappsettings.Development.json
- Development overridesappsettings.Staging.json
- Staging overridesappsettings.Production.json
- Production overridesappsettings.EndPoint.json
- Endpoint-specific configuration
Security Best Practices
Secrets Management
User Secrets for development
Azure Key Vault for production
Environment variables for containers
Configuration Validation
Strongly-typed configuration classes
Runtime validation of required settings
Fail-fast on missing critical configuration
๐๏ธ Database Strategy
Multi-Database Support
The solution supports multiple database providers:
Single Tenant
private static void EnableSingleTenant(IServiceCollection services)
{
ConfigureSingleTenantDb(services);
ConfigureFlexDb.ForRepositoryForSqlServer(services);
}
Multi Tenant
private static void EnableMultitenant(IServiceCollection services)
{
ConfigureMultiTenantMasterDb(services);
ConfigureFlexDb.ForMultitenantMasterDbForSqlServer(services);
ConfigureFlexDb.ForRepositoryForSqlServer(services);
}
Migration Strategy
Separate migration projects for each database type:
YourApplication.Migrations.SqlServer
YourApplication.Migrations.MySql
YourApplication.Migrations.PostgreSql
YourApplication.Migrations.Tenant.*
(for multi-tenant)
Database Factory Pattern
public class ApplicationEFDbContextFactory : IDesignTimeDbContextFactory<ApplicationEFDbMigrationContext>
{
public ApplicationEFDbMigrationContext CreateDbContext(string[] args)
{
// Configuration and service setup
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables().Build();
// Service collection setup
var services = new ServiceCollection();
services.AddSingleton<IConfiguration>(configuration);
// FlexBase configuration
services.AddFlexBase(new List<AssembliesToLoad> {
new AssembliesToLoad("YourApplication*.dll")
});
return serviceProvider.GetRequiredService<ApplicationEFDbMigrationContext>();
}
}
๐จ Messaging & Communication
NServiceBus Integration
The solution uses NServiceBus for reliable messaging with multiple transport options:
RabbitMQ Configuration
public class RabbitMqNsbConfiguration : NsbBaseConfiguration
{
public RabbitMqNsbConfiguration(string endpointName, IEnumerable<BusRouteConfig> routes,
IConfiguration configuration, IHostEnvironment env, string errorQueueName = "error")
: base(endpointName, configuration, env, errorQueueName)
{
// Persistence configuration
var persistence = this.UsePersistence<SqlPersistence>();
persistence.SqlDialect<SqlDialect.MsSqlServer>();
persistence.ConnectionBuilder(() => new SqlConnection(sqlPersistenceConnectionString));
// Transport configuration
var transport = this.UseTransport<RabbitMQTransport>();
transport.ConnectionString(rabbitMqConnectionString);
transport.UseConventionalRoutingTopology(QueueType.Classic);
// Routing configuration
var routing = transport.Routing();
foreach (var route in routes)
{
routing.RouteToEndpoint(route.Assembly, route.Destination);
}
}
}
Azure Service Bus Configuration
public class AzureServiceNsbConfiguration : NsbBaseConfiguration
{
public AzureServiceNsbConfiguration(string endpointName, IEnumerable<BusRouteConfig> routes,
IConfiguration configuration, IHostEnvironment env, string errorQueueName = "error")
: base(endpointName, configuration, env, errorQueueName)
{
// Azure Service Bus transport
var transport = new AzureServiceBusTransport(azureServiceBusConnectionString);
this.UseTransport(transport);
// Routing configuration
var routing = this.UseTransport(transport);
foreach (var route in routes)
{
routing.RouteToEndpoint(route.Assembly, route.Destination);
}
}
}
Message Types
Commands: Request for action
Events: Notification of something that happened
Queries: Request for data
๐ข Multi-Tenancy Support
Tenant Isolation Strategies
Database per Tenant: Complete isolation
Schema per Tenant: Shared database, separate schemas
Row-level Security: Shared database with tenant filtering
Implementation
public class TenantMigrationContext : ApplicationTenantEFDbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
var connectionString = _configuration.GetSection("FlexBase")["AppDbTenantConnection"];
optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
}
}
๐ Deployment & Scalability
Application Endpoints
The solution provides multiple deployment options:
Web API Endpoint - REST API services
Handler Endpoint - Command processing
Subscriber Endpoint - Event processing
Cron Job Endpoint - Scheduled tasks
Scalability Features
Horizontal Scaling: Multiple instances of each endpoint
Load Balancing: Built-in support for load balancers
Message Queuing: Asynchronous processing
Database Sharding: Multi-tenant database support
Caching: Ready for implementation (not yet built-in)
Container Support
Docker ready configuration
Environment variables for configuration
Health checks for monitoring
Graceful shutdown support
๐ฏ Key Benefits
For Developers
Rapid Development: Pre-built patterns and infrastructure
Type Safety: Strong typing throughout the application
Testability: Easy to unit test with dependency injection
Maintainability: Clear separation of concerns
Extensibility: Easy to add new features
For Operations
Reliability: Built-in error handling and retry mechanisms
Monitoring: Comprehensive logging and metrics
Scalability: Horizontal scaling capabilities
Security: Built-in security best practices
Deployment: Multiple deployment options
For Business
Time to Market: Faster development cycles
Cost Effective: Reduced infrastructure costs
Flexibility: Easy to adapt to changing requirements
Compliance: Built-in audit trails and security
Integration: Easy integration with external systems
๐ง Getting Started
Prerequisites
.NET 8, 9 SDK
Visual Studio 2022 or VS Code
SQL Server, MySQL, or PostgreSQL
RabbitMQ or Azure Service Bus or Azure Storage Queue Or Amazon Sqs (for messaging)
Quick Start
Clone the repository
Configure connection strings in appsettings.json
Run database migrations
Start the Web API endpoint
Start message handlers (if using messaging)
Configuration
Update appsettings.json with your database connection
Configure message bus settings
Set up logging configuration
Configure multi-tenancy (if needed)
๐ฎ Future Enhancements
Caching Strategy (Planned)
While caching is not yet implemented, the architecture is designed to easily accommodate various caching strategies:
Recommended Caching Options
Redis: Distributed caching for multi-instance scenarios
In-Memory Caching: For single-instance applications
Response Caching: HTTP response caching
Query Result Caching: Database query result caching
Implementation Approach
// Example future caching implementation
public class CachedQueryHandler<TQuery, TResult> : IQueryHandler<TQuery, TResult>
{
private readonly IQueryHandler<TQuery, TResult> _decorated;
private readonly IMemoryCache _cache;
public async Task<TResult> HandleAsync(TQuery query)
{
var cacheKey = GenerateCacheKey(query);
if (_cache.TryGetValue(cacheKey, out TResult cachedResult))
{
return cachedResult;
}
var result = await _decorated.HandleAsync(query);
_cache.Set(cacheKey, result, TimeSpan.FromMinutes(5));
return result;
}
}
Benefits of Adding Caching
Performance: Reduced database load and faster response times
Scalability: Better handling of high-traffic scenarios
Cost Efficiency: Reduced infrastructure costs
User Experience: Improved application responsiveness
Vertical Slice Architecture Enhancement (Recommended)
The current solution has a foundation for vertical slice architecture but can be enhanced to be more feature-centric:
Current State
Technical Slices: Organized by technical concerns (Handlers, Queries, Controllers)
Shared Infrastructure: Common framework and domain models
Independent Endpoints: Each capability can be deployed separately
Recommended Enhancements
1. Feature-Based Slices
YourApplication.Features/
โโโ UserManagement/
โ โโโ Controllers/
โ โโโ Commands/
โ โโโ Queries/
โ โโโ Events/
โ โโโ DTOs/
โโโ OrderProcessing/
โ โโโ Controllers/
โ โโโ Commands/
โ โโโ Queries/
โ โโโ Events/
โ โโโ DTOs/
โโโ PaymentProcessing/
โโโ Controllers/
โโโ Commands/
โโโ Queries/
โโโ Events/
โโโ DTOs/
2. Slice-Specific Infrastructure
// Each slice can have its own infrastructure
public class UserManagementSlice
{
public void ConfigureServices(IServiceCollection services)
{
// Slice-specific services
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IUserNotificationService, UserNotificationService>();
}
}
3. Cross-Slice Communication
// Events for cross-slice communication
public class UserCreatedEvent : IFlexEvent
{
public Guid UserId { get; set; }
public string Email { get; set; }
public DateTime CreatedAt { get; set; }
}
// Other slices can subscribe to events
public class OrderProcessingSlice
{
public void Handle(UserCreatedEvent @event)
{
// Create welcome order for new user
}
}
Benefits of Enhanced Vertical Slices
Business Focus: Code organization matches business domains
Team Ownership: Clear ownership boundaries
Independent Evolution: Features can evolve independently
Easier Onboarding: New developers can focus on specific business areas
Reduced Complexity: Smaller, focused codebases
This architecture documentation provides a comprehensive overview of the Flexbase solution's design patterns, best practices, and implementation strategies. The solution demonstrates enterprise-grade .NET development practices with a focus on maintainability, scalability, and developer productivity.
Last updated