Real code from BlazorBluePrint. Clean Architecture with clear separation of concerns across 5 well-structured projects.
Blazor WebAssembly frontend with MudBlazor components, dark mode, and responsive design.
ASP.NET Core Web API with versioning, Swagger documentation, and rate limiting.
CQRS command/query handlers with MediatR and FluentValidation rules.
Core entities, domain events, interfaces, and business rule constants.
EF Core persistence, Identity authentication, email, and file storage services.
Every API endpoint is protected with fine-grained permission policies. Easy to understand, easy to extend.
[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...
}
}
Clean separation of queries and commands. Each handler does one thing well.
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
});
}
}
Pages automatically check permissions. No access? No page.
@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>
All permissions defined in one place. Add new permissions in seconds.
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...
}
Get the full source code and start building your enterprise app today.