Code Samples

Real code from BlazorBluePrint. Clean Architecture with clear separation of concerns across 5 well-structured projects.

WebUI

Blazor WebAssembly frontend with MudBlazor components, dark mode, and responsive design.

API

ASP.NET Core Web API with versioning, Swagger documentation, and rate limiting.

Application

CQRS command/query handlers with MediatR and FluentValidation rules.

Domain

Core entities, domain events, interfaces, and business rule constants.

Infrastructure

EF Core persistence, Identity authentication, email, and file storage services.

Permission-Based API Endpoints

Every API endpoint is protected with fine-grained permission policies. Easy to understand, easy to extend.

UsersController.cs API
[Authorize]
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[EnableRateLimiting("api")]
public sealed class UsersController : ControllerBase
{
    private readonly IMediator _mediator;

    public UsersController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpGet]
    [Authorize(Policy = Permissions.Users.View)]
    public async Task<ActionResult<ApiResponse<IEnumerable<UserDto>>>> GetUsers()
    {
        var result = await _mediator.Send(new GetUsersQuery());

        return Ok(new ApiResponse<IEnumerable<UserDto>>
        {
            Data = result,
            Success = true,
            StatusCode = StatusCodes.Status200OK
        });
    }

    [HttpPost]
    [Authorize(Policy = Permissions.Users.Create)]
    public async Task<ActionResult<ApiResponse<UserDto>>> CreateUser(UserDto user)
    {
        // Implementation...
    }
}

CQRS with MediatR

Clean separation of queries and commands. Each handler does one thing well.

GetUsersQueryHandler.cs Application
public record GetUsersQuery : IRequest<IEnumerable<UserDto>>;

public sealed class GetUsersQueryHandler : IRequestHandler<GetUsersQuery, IEnumerable<UserDto>>
{
    private readonly UserManager<AppUser> _userManager;

    public GetUsersQueryHandler(UserManager<AppUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task<IEnumerable<UserDto>> Handle(
        GetUsersQuery request,
        CancellationToken cancellationToken)
    {
        var users = await _userManager.Users.ToListAsync(cancellationToken);

        return users.Select(user => new UserDto
        {
            Id = Guid.Parse(user.Id),
            Email = user.Email,
            UserName = user.UserName,
            FirstName = user.FirstName,
            LastName = user.LastName,
            IsEmailConfirmed = user.EmailConfirmed,
            IsLockedOut = user.LockoutEnd.HasValue && user.LockoutEnd > DateTimeOffset.UtcNow
        });
    }
}

Permission-Protected Blazor Pages

Pages automatically check permissions. No access? No page.

SecuritySettings.razor WebUI
@page "/settings/security"
@using BlazorBluePrint.Domain.Authorization
@attribute [Authorize(Policy = Permissions.Settings.ViewSecurity)]

<PageTitle>Security Settings</PageTitle>

<MudContainer MaxWidth="MaxWidth.Large" Class="mt-4">
    <MudText Typo="Typo.h4" Class="mb-4">@Localizer["SecuritySettings"]</MudText>

    <MudCard>
        <MudCardContent>
            <MudSwitch @bind-Value="settings.RequireTwoFactor"
                       Label="@Localizer["RequireTwoFactor"]"
                       Color="Color.Primary" />

            <MudTextField @bind-Value="settings.PasswordMinLength"
                          Label="@Localizer["MinPasswordLength"]"
                          Variant="Variant.Outlined" />
        </MudCardContent>
    </MudCard>
</MudContainer>

Centralized Permission Definitions

All permissions defined in one place. Add new permissions in seconds.

Permissions.cs Domain
public static class Permissions
{
    public static class Users
    {
        public const string View = "Permissions.Users.View";
        public const string Create = "Permissions.Users.Create";
        public const string Edit = "Permissions.Users.Edit";
        public const string Delete = "Permissions.Users.Delete";
    }

    public static class Roles
    {
        public const string View = "Permissions.Roles.View";
        public const string Create = "Permissions.Roles.Create";
        public const string Edit = "Permissions.Roles.Edit";
        public const string ManagePermissions = "Permissions.Roles.ManagePermissions";
    }

    public static class Settings
    {
        public const string ViewSecurity = "Permissions.Settings.ViewSecurity";
        public const string ViewTokens = "Permissions.Settings.ViewTokens";
        public const string ViewFileStorage = "Permissions.Settings.ViewFileStorage";
    }

    // Easy to add more permission groups...
}

FluentValidation Rules

Every command is validated before it runs. Clear, testable validation logic separate from your handlers.

CreateUserCommandValidator.cs Application
public class CreateUserCommandValidator : AbstractValidator<CreateUserCommand>
{
    public CreateUserCommandValidator(IUserRepository userRepository)
    {
        RuleFor(x => x.Email)
            .NotEmpty().WithMessage("Email is required")
            .EmailAddress().WithMessage("Invalid email format")
            .MustAsync(async (email, ct) =>
                !await userRepository.ExistsAsync(email, ct))
            .WithMessage("Email is already registered");

        RuleFor(x => x.FirstName)
            .NotEmpty().WithMessage("First name is required")
            .MaximumLength(100);

        RuleFor(x => x.Password)
            .NotEmpty()
            .MinimumLength(8).WithMessage("Password must be at least 8 characters")
            .Matches("[A-Z]").WithMessage("Must contain an uppercase letter")
            .Matches("[0-9]").WithMessage("Must contain a digit");
    }
}

Real-Time Notifications with SignalR

Push notifications to specific users or broadcast to all. Built-in hub with typed clients.

NotificationHub.cs Infrastructure
[Authorize]
public class NotificationHub : Hub<INotificationClient>
{
    private readonly ILogger<NotificationHub> _logger;

    public NotificationHub(ILogger<NotificationHub> logger)
    {
        _logger = logger;
    }

    public override async Task OnConnectedAsync()
    {
        var userId = Context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        if (userId != null)
        {
            await Groups.AddToGroupAsync(Context.ConnectionId, $"user-{userId}");
            _logger.LogInformation("User {UserId} connected to notifications", userId);
        }
        await base.OnConnectedAsync();
    }
}

public interface INotificationClient
{
    Task ReceiveNotification(NotificationDto notification);
    Task ReceiveToast(string message, string severity);
}

Multi-Tenant Data Isolation

Automatic per-tenant database switching. Each tenant's data is completely isolated.

TenantDbContextFactory.cs Infrastructure
public class TenantDbContextFactory : IDbContextFactory<AppDbContext>
{
    private readonly ITenantResolver _tenantResolver;
    private readonly IConfiguration _configuration;

    public TenantDbContextFactory(
        ITenantResolver tenantResolver,
        IConfiguration configuration)
    {
        _tenantResolver = tenantResolver;
        _configuration = configuration;
    }

    public AppDbContext CreateDbContext()
    {
        var tenant = _tenantResolver.GetCurrentTenant();
        var connectionString = tenant?.ConnectionString
            ?? _configuration.GetConnectionString("DefaultConnection");

        var options = new DbContextOptionsBuilder<AppDbContext>()
            .UseSqlServer(connectionString)
            .Options;

        return new AppDbContext(options, _tenantResolver);
    }
}

Hangfire Background Jobs

Schedule recurring jobs, fire-and-forget tasks, and delayed operations with automatic retries.

BackgroundJobRegistration.cs Infrastructure
public static class BackgroundJobRegistration
{
    public static void RegisterRecurringJobs()
    {
        RecurringJob.AddOrUpdate<IAuditLogCleanupJob>(
            "cleanup-audit-logs",
            job => job.ExecuteAsync(CancellationToken.None),
            Cron.Daily(2, 0),  // Run at 2:00 AM
            new RecurringJobOptions { TimeZone = TimeZoneInfo.Utc });

        RecurringJob.AddOrUpdate<IDatabaseMaintenanceJob>(
            "database-maintenance",
            job => job.ExecuteAsync(CancellationToken.None),
            Cron.Weekly(DayOfWeek.Sunday, 3, 0));

        RecurringJob.AddOrUpdate<ISystemHealthReportJob>(
            "system-health-report",
            job => job.ExecuteAsync(CancellationToken.None),
            Cron.Hourly());
    }
}

Automatic Audit Logging

Every action is tracked. Built-in audit trail with user, IP address, timestamp, and change details.

AuditableDbContext.cs Infrastructure
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
    var userId = _currentUserService.UserId;
    var auditEntries = new List<AuditEntry>();

    foreach (var entry in ChangeTracker.Entries<IAuditableEntity>())
    {
        switch (entry.State)
        {
            case EntityState.Added:
                entry.Entity.CreatedBy = userId;
                entry.Entity.CreatedOn = DateTime.UtcNow;
                auditEntries.Add(AuditEntry.ForCreate(entry, userId));
                break;

            case EntityState.Modified:
                entry.Entity.LastModifiedBy = userId;
                entry.Entity.LastModifiedOn = DateTime.UtcNow;
                auditEntries.Add(AuditEntry.ForUpdate(entry, userId));
                break;

            case EntityState.Deleted:
                auditEntries.Add(AuditEntry.ForDelete(entry, userId));
                break;
        }
    }

    var result = await base.SaveChangesAsync(cancellationToken);
    await AuditLogs.AddRangeAsync(auditEntries.Select(e => e.ToAuditLog()));
    await base.SaveChangesAsync(cancellationToken);
    return result;
}

JWT Token Generation

Secure token generation with roles, permissions, and tenant claims baked right in.

TokenService.cs Infrastructure
public async Task<TokenResponse> GenerateTokenAsync(AppUser user)
{
    var roles = await _userManager.GetRolesAsync(user);
    var permissions = await _permissionService.GetPermissionsAsync(user.Id);

    var claims = new List<Claim>
    {
        new(ClaimTypes.NameIdentifier, user.Id),
        new(ClaimTypes.Email, user.Email!),
        new("fullName", $"{user.FirstName} {user.LastName}"),
        new("tenantId", user.TenantId ?? string.Empty),
        new("avatarUrl", user.AvatarUrl ?? string.Empty)
    };

    claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r)));
    claims.AddRange(permissions.Select(p => new Claim("permission", p)));

    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret));
    var token = new JwtSecurityToken(
        issuer: _jwtSettings.Issuer,
        audience: _jwtSettings.Audience,
        claims: claims,
        expires: DateTime.UtcNow.AddMinutes(_jwtSettings.ExpiryMinutes),
        signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));

    return new TokenResponse(
        Token: new JwtSecurityTokenHandler().WriteToken(token),
        RefreshToken: GenerateRefreshToken(),
        ExpiresAt: token.ValidTo);
}

Excel & PDF Export

Export any data grid to Excel or PDF with one click. Built with ClosedXML and QuestPDF.

ExcelExportService.cs Infrastructure
public class ExcelExportService : IExcelExportService
{
    public byte[] ExportToExcel<T>(IEnumerable<T> data, string sheetName = "Sheet1")
    {
        using var workbook = new XLWorkbook();
        var worksheet = workbook.Worksheets.Add(sheetName);

        var properties = typeof(T).GetProperties()
            .Where(p => p.GetCustomAttribute<ExportIgnoreAttribute>() == null)
            .ToList();

        // Headers with styling
        for (int i = 0; i < properties.Count; i++)
        {
            var displayName = properties[i].GetCustomAttribute<DisplayNameAttribute>()?.DisplayName
                              ?? properties[i].Name;
            var cell = worksheet.Cell(1, i + 1);
            cell.Value = displayName;
            cell.Style.Font.Bold = true;
            cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#667eea");
            cell.Style.Font.FontColor = XLColor.White;
        }

        // Data rows
        var items = data.ToList();
        for (int row = 0; row < items.Count; row++)
            for (int col = 0; col < properties.Count; col++)
                worksheet.Cell(row + 2, col + 1).Value =
                    XLCellValue.FromObject(properties[col].GetValue(items[row]));

        worksheet.Columns().AdjustToContents();

        using var stream = new MemoryStream();
        workbook.SaveAs(stream);
        return stream.ToArray();
    }
}

Health Check Endpoints

Production-ready health checks for database, Hangfire, and external dependencies.

Program.cs API
builder.Services.AddHealthChecks()
    .AddSqlServer(
        connectionString: builder.Configuration.GetConnectionString("DefaultConnection")!,
        name: "database",
        tags: new[] { "ready" })
    .AddHangfire(options =>
    {
        options.MinimumAvailableServers = 1;
    }, name: "hangfire", tags: new[] { "ready" })
    .AddCheck<DiskStorageHealthCheck>("disk-storage", tags: new[] { "ready" });

// Map endpoints
app.MapHealthChecks("/health", new HealthCheckOptions
{
    Predicate = _ => true,
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
    Predicate = check => check.Tags.Contains("ready")
});

Dark Mode & Theme Switching

Toggle between light and dark themes with persisted user preference. Custom MudBlazor theme throughout.

MainLayout.razor WebUI
<MudThemeProvider @ref="_themeProvider" Theme="_theme" IsDarkMode="@_isDarkMode" />

@code {
    private MudThemeProvider _themeProvider = null!;
    private bool _isDarkMode;

    private readonly MudTheme _theme = new()
    {
        PaletteLight = new PaletteLight
        {
            Primary = "#667eea",
            Secondary = "#764ba2",
            AppbarBackground = "#667eea",
            DrawerBackground = "#f8f9fa"
        },
        PaletteDark = new PaletteDark
        {
            Primary = "#667eea",
            Secondary = "#764ba2",
            Surface = "#1e1e2d",
            Background = "#151521",
            DrawerBackground = "#1e1e2d"
        }
    };

    private async Task ToggleDarkMode()
    {
        _isDarkMode = !_isDarkMode;
        await LocalStorage.SetItemAsync("darkMode", _isDarkMode);
    }
}

Multi-Language Localization

15+ languages out of the box. Switch languages at runtime with a single click.

LanguageSelector.razor WebUI
<MudMenu Icon="@Icons.Material.Filled.Language" Color="Color.Inherit">
    @foreach (var culture in SupportedCultures)
    {
        <MudMenuItem OnClick="@(() => SetCulture(culture))">
            <div class="d-flex align-center gap-2">
                <MudImage Src="@($"images/flags/{culture.Name}.svg")"
                          Width="20" Height="15" />
                @culture.NativeName
            </div>
        </MudMenuItem>
    }
</MudMenu>

@code {
    private CultureInfo[] SupportedCultures => new[]
    {
        new CultureInfo("en-US"), new CultureInfo("es-ES"),
        new CultureInfo("fr-FR"), new CultureInfo("de-DE"),
        new CultureInfo("pt-BR"), new CultureInfo("ja-JP"),
        new CultureInfo("zh-CN"), new CultureInfo("ko-KR"),
        new CultureInfo("ar-SA"), new CultureInfo("hi-IN"),
        // ... 15+ languages supported
    };
}

Docker Compose Deployment

One command to deploy. Production-ready Docker setup with health checks and auto-restart.

docker-compose.yml Docker
services:
  db:
    image: mcr.microsoft.com/mssql/server:2022-latest
    environment:
      SA_PASSWORD: ${DB_PASSWORD}
      ACCEPT_EULA: "Y"
    volumes:
      - sqldata:/var/opt/mssql
    healthcheck:
      test: /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$$SA_PASSWORD" -Q "SELECT 1" -C
      interval: 10s
      retries: 5

  app:
    build: .
    ports:
      - "5000:8080"
    environment:
      - ConnectionStrings__DefaultConnection=Server=db;Database=BlazorBluePrint;User=sa;Password=${DB_PASSWORD};TrustServerCertificate=true
      - JwtSettings__Secret=${JWT_SECRET}
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: curl -f http://localhost:8080/health || exit 1
      interval: 30s
      retries: 3

volumes:
  sqldata:

Ready to Build?

Get the full source code and start building your enterprise app today.