Domain concepts like priority, category, and status are the vocabulary of your business. In the MVC Project Manager's Todo feature, these are modeled as C# enums — TodoPriority with Low/Medium/High and TodoCategory with Personal/Work/Learning. This part shows how enums work end-to-end in VSA: how they're defined, validated, stored in the database, filtered in queries, and rendered in both Blazor and Vue.js frontends.
The decision to use enums instead of lookup tables is a deliberate VSA choice. Enums live in the feature's namespace, travel with the feature's DTOs, and are validated by the feature's validators. Lookup tables belong to the layered-architecture world where shared reference data is managed centrally. In VSA, each feature owns its domain vocabulary — no cross-feature coupling over reference data.
Defining the Enums
The enums are defined in the Todo feature's namespace, alongside the entity and handlers:
public enum TodoPriority
{
Low = 0,
Medium = 1,
High = 2
}
public enum TodoCategory
{
Personal = 0,
Work = 1,
Learning = 2
}
Explicit integer values keep the database representation stable even if you reorder the enum later. The entity uses these enum types directly, and EF Core stores them as integers by default — compact and indexable.
Validating Enum Values
FluentValidation's IsInEnum() ensures the client can't send invalid values. This is critical because JSON deserialization happily maps an integer like 99 into an enum even if no such value exists:
RuleFor(x => x.Priority)
.IsInEnum().WithMessage("Priority must be a valid value");
RuleFor(x => x.Category)
.IsInEnum().WithMessage("Category must be a valid value");
The validator runs in the handler (Part 4), so invalid enum values are rejected before any data is written. Without IsInEnum(), an out-of-range enum would silently pass validation and corrupt your data with an undefined value.
Storing Enums in EF Core
By default, EF Core stores enums as integers. This is compact and efficient, but the raw values are meaningless in the database. For readability, you can configure a value converter to store enum names as strings:
entity.Property(e => e.Priority)
.HasConversion<string>()
.HasMaxLength(20);
entity.Property(e => e.Category)
.HasConversion<string>()
.HasMaxLength(20);
Storing as strings makes the database self-documenting ("Medium", "Work") at the cost of slightly larger storage and marginally slower indexing. For the Todo feature, either strategy works — the choice is about database readability vs performance. The key point is that the decision is made once in OnModelCreating, and handlers never see the difference.
Enum-Based Filtering in Queries
The list handler filters by enum values. The MVC Project Manager's search supports filtering by priority and category. A subtle challenge: EF Core can't translate Enum.ToString() to SQL, so the handler pre-filters enum values client-side and builds an IN clause:
// Enum-based filtering in GetTodoListHandler
if (priorityValues.Count > 0)
{
query = query.Where(x => priorityValues.Contains(x.Priority));
}
if (categoryValues.Count > 0)
{
query = query.Where(x => categoryValues.Contains(x.Category));
}
This works because enums are stored as integers — the Contains on a list of enum values translates to a simple WHERE Priority IN (0, 1, 2). The handler exposes these filters to the frontend, enabling dropdown-based filtering in the DataTable.
Rendering Enums in Blazor (MudBlazor)
In the Blazor frontend, enums render as color-coded chips. The status is derived from the IsCompleted flag, and priority/category map to colored MudChip components:
@if (context.IsCompleted)
{
<MudChip Color="Color.Success" Size="Size.Small" Variant="Variant.Text"
Style="font-weight: 600;">COMPLETED</MudChip>
}
else
{
<MudChip Color="Color.Warning" Size="Size.Small" Variant="Variant.Text"
Style="font-weight: 600;">PENDING</MudChip>
}
For dropdowns, the create/update forms bind enum values directly to MudSelect components. Because the DTOs are in the same assembly (single-project VSA), Blazor can enumerate Enum.GetValues<TodoPriority>() directly — no separate lookup endpoint needed.
Rendering Enums in Vue.js (MVC)
The MVC frontend uses Tom Select for enum dropdowns and custom render functions for badges. The Vue data model stores enum names as strings ("Medium", "Work"), matching the JSON serialization. The DataTables render function maps each enum name to a colored badge:
function priorityBadge(data) {
const colors = {
Low: 'bg-secondary', Medium: 'bg-warning', High: 'bg-danger'
};
return `<span class="badge ${colors[data] || 'bg-secondary'}">${data}</span>`;
}
The category cards in the create form (Personal/Work/Learning) use visual icons — each category is a selectable card with an icon and label. The selected category updates the Vue form model, which submits as part of the JSON payload to the VSA handler.