Skip to main content

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:
builder.Services.AddHeroCaching(configuration);
builder.Services.AddHeroJobs();
builder.Services.AddHeroMailing();
builder.Services.AddHeroStorage(configuration);

Best Practices

1

Use Interfaces

Always depend on abstractions (ICacheService, IJobService) not concrete types.
2

Leverage DI

All Building Block services are registered in the DI container. Inject them via constructors.
3

Follow Naming Conventions

Extension methods use AddHero* and UseHero* prefixes for consistency.
4

Configure via appsettings.json

Building Blocks bind configuration from appsettings.json using IOptions<T> pattern.

Configuration Example

appsettings.json
{
  "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

Build docs developers (and LLMs) love