What are Building Blocks?
Building Blocks are the foundational infrastructure packages of the FullStackHero .NET Starter Kit. They provide reusable, production-ready implementations of common enterprise patterns and cross-cutting concerns.
Building Blocks are protected — modify with caution. They are designed to be stable, reusable, and shared across all modules.
Architecture
Building Blocks follow a layered architecture:
Modules (Business Logic)
↓ depends on
Building Blocks (Infrastructure)
↓ depends on
.NET BCL + Third-party libraries
Available Building Blocks
Core DDD primitives, entities, domain events, exceptions
Persistence Repository pattern, specifications, EF Core extensions
Caching Hybrid L1/L2 cache with Redis support
Mailing SMTP and SendGrid email providers
Jobs Background job processing with Hangfire
Storage Local and S3 file storage abstractions
Eventing Domain events, integration events, outbox pattern
Web ASP.NET Core extensions, OpenAPI, CORS, auth
Design Principles
1. Abstraction over Implementation
Building Blocks expose clean interfaces and hide implementation details:
public interface IStorageService
{
Task < string > UploadAsync < T >( FileUploadRequest request ,
FileType fileType , CancellationToken ct );
}
// Swap implementations without changing consumers
services . AddHeroLocalFileStorage (); // or
services . AddHeroStorage ( configuration ); // S3
2. Convention over Configuration
Sensible defaults with opt-in customization:
builder . AddHeroPlatform ( options =>
{
options . EnableCaching = true ; // Opt-in
options . EnableJobs = true ; // Opt-in
options . EnableMailing = false ; // Default off
});
3. Multi-Tenancy First
All Building Blocks respect tenant isolation:
public interface IDomainEvent
{
string ? TenantId { get ; }
}
public interface IIntegrationEvent
{
string ? TenantId { get ; }
}
4. Testability
All abstractions are mockable and testable:
public class MyServiceTests
{
[ Fact ]
public async Task Should_Cache_Result ()
{
var mockCache = Substitute . For < ICacheService >();
var service = new MyService ( mockCache );
// Test without real Redis
}
}
Package Structure
src/BuildingBlocks/
├── Core/ # Domain primitives
├── Persistence/ # Data access patterns
├── Caching/ # Distributed caching
├── Mailing/ # Email services
├── Jobs/ # Background processing
├── Storage/ # File management
├── Eventing/ # Event-driven messaging
├── Eventing.Abstractions/ # Event contracts
├── Web/ # ASP.NET Core extensions
├── Shared/ # Cross-cutting DTOs
└── Blazor.UI/ # Blazor components
Adding to Your Module
Reference Building Blocks in your module’s .csproj:
< ItemGroup >
< ProjectReference Include = "..\..\BuildingBlocks\Core\FSH.Framework.Core.csproj" />
< ProjectReference Include = "..\..\BuildingBlocks\Persistence\FSH.Framework.Persistence.csproj" />
</ ItemGroup >
Extension Methods Pattern
All Building Blocks follow a consistent registration pattern:
Services Registration
Middleware Registration
builder . Services . AddHeroCaching ( configuration );
builder . Services . AddHeroJobs ();
builder . Services . AddHeroMailing ();
builder . Services . AddHeroStorage ( configuration );
Best Practices
Use Interfaces
Always depend on abstractions (ICacheService, IJobService) not concrete types.
Leverage DI
All Building Block services are registered in the DI container. Inject them via constructors.
Follow Naming Conventions
Extension methods use AddHero* and UseHero* prefixes for consistency.
Configure via appsettings.json
Building Blocks bind configuration from appsettings.json using IOptions<T> pattern.
Configuration Example
{
"CachingOptions" : {
"Redis" : "localhost:6379" ,
"EnableSsl" : false ,
"DefaultSlidingExpiration" : "00:05:00"
},
"HangfireOptions" : {
"Route" : "/jobs" ,
"UserName" : "admin" ,
"Password" : "admin"
},
"MailOptions" : {
"UseSendGrid" : false ,
"From" : "[email protected] " ,
"DisplayName" : "FSH Application"
}
}
Next Steps
Core Primitives Learn about DDD entities, value objects, and domain events
Persistence Layer Master repository patterns and specifications
Web Extensions Configure OpenAPI, CORS, rate limiting, and more
Event-Driven Design Implement outbox pattern and integration events