### Install Blazilla via NuGet
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Use this command to add the Blazilla package to your project using the .NET CLI.
```bash
dotnet add package Blazilla
```
--------------------------------
### Manual Async Validation Handling in Blazored.FluentValidation
Source: https://github.com/loresoft/blazilla/blob/main/README.md
This example shows the manual approach to handling async validation required by Blazored.FluentValidation.
```razor
@code {
private FluentValidationValidator? validator;
private bool isValidating;
private async Task HandleValidSubmit()
{
// Manual async validation handling
if (validator != null)
{
isValidating = true;
await Task.Delay(100); // Wait for async validation
isValidating = false;
}
// Process form
}
}
```
--------------------------------
### Setup Blazor Server with FluentValidation
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/integration-patterns.md
Configure Blazor Server application services, including Razor Pages, Blazor Server, and FluentValidation validators. This setup is essential for enabling server-side validation in your Blazor application.
```csharp
using FluentValidation;
using Blazilla.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
// Register validators
builder.Services.AddSingleton, PersonValidator>();
var app = builder.Build();
app.MapBlazorHub();
app.Run();
```
--------------------------------
### PathResolver FindField Examples
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathResolver.md
Demonstrates how to use the PathResolver.FindField method to locate properties, nested properties, and collection items within an object.
```csharp
var person = new Person
{
FirstName = "Alice",
Address = new Address { Street = "Oak Ave" },
PhoneNumbers = new List
{
new PhoneNumber { Number = "555-1234" }
}
};
// Simple property
var field1 = PathResolver.FindField(person, "FirstName");
// Returns: FieldIdentifier(person, "FirstName")
// Nested property
var field2 = PathResolver.FindField(person, "Address.Street");
// Returns: FieldIdentifier(person.Address, "Street")
// Collection item
var field3 = PathResolver.FindField(person, "PhoneNumbers[0].Number");
// Returns: FieldIdentifier(person.PhoneNumbers[0], "Number")
```
--------------------------------
### Attribute-Based Registration with Injectio
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Utilize the Injectio package for attribute-based registration. Apply attributes like `[RegisterSingleton]` directly to validator classes for simplified DI setup.
```csharp
// Install: dotnet add package Injectio
// Add attribute to each validator class
[RegisterSingleton>]
public class PersonValidator : AbstractValidator
{
// validator implementation
}
```
--------------------------------
### PathValue Deconstruction Example
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/types.md
Demonstrates how to deconstruct a PathValue record struct into its constituent parts using tuple deconstruction syntax.
```csharp
var (name, sep, isIndexer) = pathValue;
```
--------------------------------
### Method Chaining for Validator Registration
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/ServiceCollectionExtensions.md
Demonstrates chaining multiple validator registration methods on the ServiceCollection for efficient setup.
```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddValidatorsFromAssemblyContaining()
.AddValidatorsFromAssemblyContaining()
.AddValidatorsFromAssemblies(new[] {
typeof(Program).Assembly,
typeof(ExternalValidator).Assembly
});
```
--------------------------------
### CurrentName
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Gets the top path segment from the stack as a formatted string.
```APIDOC
## CurrentName()
### Description
Gets the top path segment from the stack as a formatted string.
### Method
`CurrentName`
### Returns
- `string`: For property segments, the property name. For indexer segments, the full indexer path (e.g., `[0]`) if it's the only item. For indexer segments followed by properties, the indexer plus preceding indexers (e.g., `Companies[0].Name` returns the property name part).
- Returns an empty string if the stack is empty.
### Request Example
```csharp
var pathStack = new PathStack();
pathStack.PushProperty("Address");
pathStack.PushProperty("Street");
Console.WriteLine(pathStack.CurrentName()); // "Street"
pathStack.Clear();
pathStack.PushIndex(0);
Console.WriteLine(pathStack.CurrentName()); // "[0]"
```
```
--------------------------------
### Install Blazilla via Package Manager Console
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Use this command to add the Blazilla package to your project using the Package Manager Console in Visual Studio.
```powershell
Install-Package Blazilla
```
--------------------------------
### Create Indexer PathValue Instance
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/types.md
Example of creating a PathValue instance to represent an indexer access in a path. It uses a numeric string for the name and sets Indexer to true.
```csharp
// Indexer path component
var indexerPath = new PathValue("0", Separator: null, Indexer: true);
```
--------------------------------
### Create Property PathValue Instance
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/types.md
Example of creating a PathValue instance to represent a property access in a path. It specifies the property name, separator, and explicitly sets Indexer to false.
```csharp
// Property path component
var propertyPath = new PathValue("FirstName", Separator: '.', Indexer: false);
```
--------------------------------
### Blazor FieldIdentifier to FluentValidation Path Conversion Examples
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Illustrates how Blazilla converts Blazor's FieldIdentifier to FluentValidation property paths for simple properties, nested properties, and collection items.
```csharp
// Blazor FieldIdentifier: { Model = person, FieldName = "FirstName" }
// FluentValidation path: "FirstName"
```
```csharp
// Blazor FieldIdentifier: { Model = address, FieldName = "Street" }
// FluentValidation path: "Address.Street" (when address is a property of person)
```
```csharp
// Blazor FieldIdentifier: { Model = phoneNumber, FieldName = "Number" }
// FluentValidation path: "PhoneNumbers[0].Number" (when phoneNumber is item 0 in a collection)
```
--------------------------------
### PathValue Immutability Example
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/types.md
Illustrates the immutability of record structs. Attempting to modify a property directly will result in a compile-time error. Instead, a new instance must be created using the 'with' expression.
```csharp
var value = new PathValue("Street", Separator: '.', Indexer: false);
// value.Name = "Avenue"; // ERROR: record structs are immutable
// Create new instance instead:
var updated = value with { Name = "Avenue" };
```
--------------------------------
### Nested Object Validation Example
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/FluentValidator.md
Demonstrates how FluentValidator correctly maps validation messages for nested objects by reconstructing property paths.
```csharp
public class Person
{
public string FirstName { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
}
// When validating Address.Street, the component maps it correctly
// even when the Address object is nested within Person
```
--------------------------------
### Log Output for Missing Validator
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Example log output indicating that no validator was found for a given model type. This warning helps identify missing validator registrations.
```log
warn: Blazilla.FluentValidator[0]
No validator found for model type MyApp.Models.Person. To use FluentValidator, register a validator for this model type or pass one directly to the Validator parameter.
```
--------------------------------
### Automatic Validator Registration with FluentValidation Extensions
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Use FluentValidation's DI extensions to automatically scan assemblies and register all validators. Ensure the `FluentValidation.DependencyInjectionExtensions` package is installed.
```csharp
// Install: dotnet add package FluentValidation.DependencyInjectionExtensions
// Scans assembly and registers all validators
services.AddValidatorsFromAssemblyContaining();
```
--------------------------------
### Implement Custom Validator Selector
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/integration-patterns.md
Create a class that implements `IValidatorSelector` to define custom logic for executing validation rules. This example skips 'Optional' rules unless a specific flag is set.
```csharp
public class ConditionalSelector : IValidatorSelector
{
private readonly bool _requireOptionalFields;
public ConditionalSelector(bool requireOptionalFields)
{
_requireOptionalFields = requireOptionalFields;
}
public bool CanExecute(
IValidationRule rule,
string propertyPath,
IValidationContext context)
{
// Skip optional validation unless flag is set
if (!_requireOptionalFields && rule.RuleSets.Contains("Optional"))
return false;
return true;
}
}
```
--------------------------------
### Register Validators from Multiple Assemblies
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/ServiceCollectionExtensions.md
Example of using AddValidatorsFromAssemblies to register validators from the current application assembly and another specified assembly. Note the [RequiresUnreferencedCode] attribute, indicating this method is not trim-safe.
```csharp
var builder = WebApplication.CreateBuilder(args);
var currentAssembly = typeof(Program).Assembly;
var validatorAssembly = typeof(PersonValidator).Assembly;
builder.Services.AddValidatorsFromAssemblies(
new[] { currentAssembly, validatorAssembly });
```
--------------------------------
### Register Validators from a Single Assembly
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/ServiceCollectionExtensions.md
Example of using AddValidatorsFromAssembly to register validators from the current assembly. This method discovers types inheriting from AbstractValidator. Note the [RequiresUnreferencedCode] attribute, indicating this method is not trim-safe.
```csharp
var builder = WebApplication.CreateBuilder(args);
// Scan the current assembly
builder.Services.AddValidatorsFromAssembly(typeof(Program).Assembly);
// With custom lifetime
builder.Services.AddValidatorsFromAssembly(
typeof(PersonValidator).Assembly,
lifetime: ServiceLifetime.Transient);
```
--------------------------------
### Get Current Property from PathStack
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Use CurrentProperty to get the most recent non-indexer property name from the stack. Returns an empty string if no properties are present.
```csharp
var pathStack = new PathStack();
pathStack.PushProperty("Items");
pathStack.PushIndex(0);
pathStack.PushProperty("Name");
Console.WriteLine(pathStack.CurrentProperty()); // "Name"
```
--------------------------------
### CurrentProperty
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Gets the top non-indexer property name from the stack.
```APIDOC
## CurrentProperty()
### Description
Gets the top non-indexer property name from the stack.
### Method
`CurrentProperty`
### Returns
- `string`: The name of the most recent property segment.
- Returns an empty string if no properties are on the stack.
### Request Example
```csharp
var pathStack = new PathStack();
pathStack.PushProperty("Items");
pathStack.PushIndex(0);
pathStack.PushProperty("Name");
Console.WriteLine(pathStack.CurrentProperty()); // "Name"
```
```
--------------------------------
### Pushing Segments and Building Path
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Demonstrates how to push property segments onto the PathStack and convert it into a FluentValidation-compatible path string. This is used when navigating object graphs to identify specific properties.
```csharp
// FluentValidation path
"Address.Street"
// Converts to PathStack representation
stack.PushProperty("Address")
stack.PushProperty("Street")
stack.ToString() → "Address.Street"
// Used in ValidationFailure
validationFailure.PropertyName = "Address.Street"
// Maps to Blazor field
FieldIdentifier(person.Address, "Street")
```
--------------------------------
### Assembly Scanning with Scrutor
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Employ the Scrutor package for flexible assembly scanning to discover and register validators. This approach allows for custom filtering and mapping of implementations to interfaces.
```csharp
// Install: dotnet add package Scrutor
services.Scan(scan => scan
.FromAssemblyOf()
.AddClasses(classes => classes.AssignableTo(typeof(IValidator<>)))
.AsImplementedInterfaces()
.WithSingletonLifetime());
```
--------------------------------
### Get Current Name from PathStack
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Use CurrentName to retrieve the top path segment. It formats indexers appropriately, like '[0]'.
```csharp
var pathStack = new PathStack();
pathStack.PushProperty("Address");
pathStack.PushProperty("Street");
Console.WriteLine(pathStack.CurrentName()); // "Street"
pathStack.Clear();
pathStack.PushIndex(0);
Console.WriteLine(pathStack.CurrentName()); // "[0]"
```
--------------------------------
### Validator with Asynchronous Rule
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Define asynchronous validation rules within a FluentValidation validator. This example simulates a delay for a database check.
```csharp
public class PersonValidator : AbstractValidator
{
public PersonValidator()
{
RuleFor(p => p.EmailAddress)
.NotEmpty().WithMessage("Email is required")
.EmailAddress().WithMessage("Please provide a valid email address")
.MustAsync(async (email, cancellation) =>
{
// Simulate async validation (e.g., database check)
await Task.Delay(500, cancellation);
return !email?.Equals("admin@example.com", StringComparison.OrdinalIgnoreCase) ?? true;
}).WithMessage("This email address is not available");
}
}
```
--------------------------------
### Publish Blazor WebAssembly with AOT Compilation
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/integration-patterns.md
Command to publish a Blazor WebAssembly application with Ahead-of-Time (AOT) compilation enabled.
```bash
dotnet publish -c Release -p:RunAOTCompilation=true
```
--------------------------------
### ElementAt: Get element by index
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/EnumerableExtensions.md
Retrieves the element at a specific index from an IEnumerable. Throws an exception if the index is invalid or the source is null. Optimized for arrays and lists.
```csharp
public static object ElementAt(this IEnumerable source, int index)
{
// Implementation details omitted for brevity
throw new NotImplementedException();
}
```
```csharp
var list = new List { 10, 20, 30 };
object element = list.ElementAt(1); // Returns 20
var array = new[] { "a", "b", "c" };
object item = array.ElementAt(0); // Returns "a"
// Throws ArgumentOutOfRangeException
// var outOfRange = list.ElementAt(10);
// Throws ArgumentOutOfRangeException
// var negative = list.ElementAt(-1);
// Throws ArgumentNullException
// IEnumerable nullSource = null;
// var nullResult = nullSource.ElementAt(0);
```
--------------------------------
### Blazor WebAssembly Bootstrapping Script
Source: https://github.com/loresoft/blazilla/blob/main/samples/BlazorWebAssembly/wwwroot/index.html
This script block is responsible for loading the Blazor runtime and bootstrapping the Blazor application. It dynamically creates a script element to load the Blazor.web.js file.
```html
```
--------------------------------
### Production Logging and Manual Validator Registration
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/configuration.md
For production, configure minimal information-level logging and use manual registration for predictability and Ahead-of-Time (AOT) compilation safety.
```csharp
// Use manual registration for predictability and AOT safety
builder.Services.AddSingleton, PersonValidator>();
builder.Services.AddSingleton, AddressValidator>();
// Only enable info-level logging
builder.Services.AddLogging(logging =>
{
logging.SetMinimumLevel(LogLevel.Information);
});
```
--------------------------------
### ElementAtOrDefault: Get element by index or default
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/EnumerableExtensions.md
Retrieves the element at a specific index from an IEnumerable, returning null if the index is out of range or the source is null. Optimized for arrays and lists.
```csharp
public static object? ElementAtOrDefault(this IEnumerable source, int index)
{
// Implementation details omitted for brevity
throw new NotImplementedException();
}
```
```csharp
var list = new List { 10, 20, 30 };
// Valid index
object? element = list.ElementAtOrDefault(1); // Returns 20
// Out of range
object? outOfRange = list.ElementAtOrDefault(10); // Returns null
// Negative index
object? negative = list.ElementAtOrDefault(-1); // Returns null
// Null source
IEnumerable? nullSource = null;
object? nullResult = nullSource.ElementAtOrDefault(0); // Returns null
// Custom enumerable
var enumerable = Enumerable.Range(0, 5);
object? fromEnumerable = enumerable.ElementAtOrDefault(2); // Returns 2
```
--------------------------------
### Safely Use PathResolver
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Implement try-catch blocks to handle potential exceptions like ArgumentNullException when using PathResolver, ensuring graceful failure.
```csharp
private string? TryResolvePath()
{
try
{
var resolver = new PathResolver();
return resolver.FindPath(rootObject, fieldIdentifier);
}
catch (ArgumentNullException ex)
{
// Log or handle null argument
Logger.LogError(ex, "Path resolution failed due to null argument");
return null;
}
}
```
--------------------------------
### Implement Custom Validator Selector
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Use a custom IValidatorSelector to implement fine-grained control over which validation rules are executed. This example shows how to define a basic custom selector.
```razor
@code {
private IValidatorSelector customSelector = new CustomValidatorSelector();
public class CustomValidatorSelector : IValidatorSelector
{
public bool CanExecute(IValidationRule rule, string propertyPath, IValidationContext context)
{
// Custom logic to determine if a rule should execute
return true;
}
}
}
```
--------------------------------
### ToString
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Serializes the entire path stack into a dot-notation path string.
```APIDOC
## ToString()
### Description
Serializes the entire path stack into a dot-notation path string compatible with FluentValidation.
### Method
`ToString`
### Returns
- `string`: The complete path expression (e.g., "Address.Street", "Items[0].Name", "Companies[0].Address.Street").
- Returns an empty string if the stack is empty.
### Request Example
```csharp
var pathStack = new PathStack();
pathStack.PushProperty("Person");
pathStack.PushProperty("Address");
pathStack.PushProperty("Street");
Console.WriteLine(pathStack.ToString()); // "Person.Address.Street"
var pathStack2 = new PathStack();
pathStack2.PushProperty("Items");
pathStack2.PushIndex(0);
pathStack2.PushProperty("Value");
Console.WriteLine(pathStack2.ToString()); // "Items[0].Value"
```
```
--------------------------------
### PushProperty
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Pushes a property name onto the stack, separated by a dot.
```APIDOC
## PushProperty(string)
### Description
Pushes a property name onto the stack with a dot separator.
### Method
`PushProperty`
### Parameters
#### Path Parameters
- **propertyName** (string) - Required - The name of the property to push. Empty or null values are converted to an empty string.
### Request Example
```csharp
var pathStack = new PathStack();
pathStack.PushProperty("Address");
pathStack.PushProperty("Street");
// Stack represents: "Address.Street"
```
```
--------------------------------
### OnInitialized Method
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/FluentValidator.md
Initializes the FluentValidator component. It sets up the validation context, resolves the validator, and subscribes to relevant EditContext events. Ensure an EditContext is available.
```csharp
protected override void OnInitialized()
```
--------------------------------
### Avoiding ArgumentNullException in PathResolver.FindPath (null targetInstance)
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Demonstrates how to correctly call the PathResolver.FindPath overload by ensuring the target instance is not null. Passing null for targetInstance will throw an ArgumentNullException.
```csharp
var resolver = new PathResolver();
var person = new Person { Address = new Address() };
// Wrong
var path = resolver.FindPath(person, null, "Street"); // Throws
// Correct
var path = resolver.FindPath(person, person.Address, "Street");
```
--------------------------------
### PushKey
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Pushes a key value onto the stack, marking it as an indexer for dictionary-style access.
```APIDOC
## PushKey(T)
### Description
Pushes a key value onto the stack and marks it as an indexer. Semantically equivalent to `PushIndex` for dictionary-style key access.
### Method
`PushKey`
### Parameters
#### Path Parameters
- **key** (T) - Required - The key value. Converted to string using `ToString()`. Null values become an empty string.
### Type Parameters
- **T**: The type of the key value (typically `string` for dictionary keys).
### Request Example
```csharp
var pathStack = new PathStack();
pathStack.PushProperty("Properties");
pathStack.PushKey("theme");
// Stack represents: "Properties[theme]"
```
```
--------------------------------
### Capture Exception Details in C#
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Use a try-catch block to capture and log essential exception details like type, message, and stack trace. Include model and configuration details for comprehensive error reporting.
```csharp
try
{
// Your Blazilla code
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.GetType().Name}");
Console.WriteLine($"Message: {ex.Message}");
Console.WriteLine($"Stack: {ex.StackTrace}");
// Include model and configuration details
}
```
--------------------------------
### Integrate FluentValidator in Blazor EditForm
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Use the FluentValidator component within a Blazor EditForm to enable validation for the bound model. This example shows how to bind nested properties like Address.Street.
```razor
```
--------------------------------
### Using Generic Overload for Validator Registration
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/ServiceCollectionExtensions.md
Illustrates the preferred generic overload for registering validators from a specific assembly.
```csharp
services.AddValidatorsFromAssemblyContaining();
```
```csharp
services.AddValidatorsFromAssemblyContaining(typeof(PersonValidator));
```
--------------------------------
### Use Validator in Blazor Component
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Integrate the FluentValidation validator into a Blazor component using EditForm and FluentValidator. This example shows input fields for Person properties and displays validation messages.
```razor
@page "/person-form"
Person Form
@code {
private Person person = new();
private async Task HandleValidSubmit()
{
// Handle successful form submission
Console.WriteLine("Form submitted successfully!");
}
}
```
--------------------------------
### Safely Access Collection Items
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Demonstrates safe collection access using try-catch for ArgumentOutOfRangeException and ArgumentNullException, and highlights the preferred ElementAtOrDefault method.
```csharp
private object? SafeGetCollectionItem(IEnumerable source, int index)
{
try
{
return source.ElementAt(index);
}
catch (ArgumentOutOfRangeException)
{
// Index was out of range
return null;
}
catch (ArgumentNullException)
{
// Source was null
return null;
}
}
// Preferred - use ElementAtOrDefault
private object? SafeGetCollectionItem(IEnumerable source, int index)
{
return source?.ElementAtOrDefault(index);
}
```
--------------------------------
### Blazored.FluentValidation - No Registration Needed
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Illustrates that Blazored.FluentValidation automatically scans assemblies for validators at runtime, requiring no explicit registration.
```csharp
// No registration needed - Blazored.FluentValidation automatically
// scans assemblies and finds validators at runtime
```
--------------------------------
### Push Key onto PathStack
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Use PushKey to add a dictionary-style key to the path, enclosed in brackets. This is semantically similar to PushIndex.
```csharp
var pathStack = new PathStack();
pathStack.PushProperty("Properties");
pathStack.PushKey("theme");
// Stack represents: "Properties[theme]"
```
--------------------------------
### Development Logging and Validator Registration
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/configuration.md
In development, enable detailed debug logging and use assembly scanning for convenient validator registration.
```csharp
// Enable detailed logging for debugging
builder.Services.AddLogging(logging =>
{
logging.SetMinimumLevel(LogLevel.Debug);
logging.AddConsole();
});
// Use assembly scanning for convenience
builder.Services.AddValidatorsFromAssemblyContaining();
```
--------------------------------
### Manual Validator Registration in DI
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Register each validator individually in the dependency injection container. This is simple but can be tedious for many validators.
```csharp
// Manual registration (simple but tedious for many validators)
builder.Services.AddSingleton, PersonValidator>();
builder.Services.AddSingleton, CompanyValidator>();
builder.Services.AddSingleton, AddressValidator>();
// ... register all validators used in your application
```
--------------------------------
### PathResolver Usage with ElementAtOrDefault
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/EnumerableExtensions.md
Demonstrates how PathResolver uses ElementAtOrDefault to navigate through nested collections and access specific elements by index.
```csharp
// Example object graph
var person = new Person
{
PhoneNumbers = new List
{
new PhoneNumber { Number = "555-1234" },
new PhoneNumber { Number = "555-5678" }
}
};
// PathResolver uses ElementAtOrDefault internally to navigate:
// 1. Find "PhoneNumbers" property → returns the list
// 2. Use ElementAtOrDefault(0) → returns first PhoneNumber
// 3. Continue with "Number" property → returns "555-1234"
var fieldIdentifier = new FieldIdentifier(person.PhoneNumbers[0], "Number");
var path = resolver.FindPath(person, fieldIdentifier);
// Result: "PhoneNumbers[0].Number"
```
--------------------------------
### Avoiding ArgumentNullException in PathResolver.FindPath (null rootObject)
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Demonstrates how to correctly call PathResolver.FindPath by ensuring the root object is not null. Passing null for rootObject will throw an ArgumentNullException.
```csharp
var resolver = new PathResolver();
// Wrong
FieldIdentifier fieldId = new(person.Address, "Street");
var path = resolver.FindPath(null, fieldId); // Throws
// Correct
var rootPerson = person; // Ensure not null
var path = resolver.FindPath(rootPerson, fieldId);
```
--------------------------------
### Single Access Performance Optimization
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/EnumerableExtensions.md
Shows how to achieve maximum performance for single access by using FirstOrDefault on an enumerable, which is equivalent to ElementAtOrDefault(0).
```csharp
// Using extension method
var item = enumerable.ElementAtOrDefault(0);
// Equivalent inline for maximum performance
var item = enumerable.FirstOrDefault();
```
--------------------------------
### IList Fast Path Optimization
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/EnumerableExtensions.md
Implements direct O(1) access for IList implementations using the indexer. Returns null if the index is out of bounds.
```csharp
if (source is IList list)
return index < list.Count ? list[index] : null;
```
--------------------------------
### Accessing Nested Collections with PathResolver
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/EnumerableExtensions.md
Demonstrates how PathResolver can access elements within nested collections using indexers. Each index access relies on the ElementAtOrDefault method for safe retrieval.
```csharp
// Support for nested collections
person.Companies[0].Addresses[1].Street
// Each index access uses ElementAtOrDefault:
// companies.ElementAtOrDefault(0) → Company at index 0
// addresses.ElementAtOrDefault(1) → Address at index 1
```
--------------------------------
### Avoiding ArgumentNullException in PathResolver.FindPath (null targetProperty)
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Demonstrates how to correctly call PathResolver.FindPath by providing a non-null target property name. Passing null for targetProperty will throw an ArgumentNullException.
```csharp
var resolver = new PathResolver();
// Wrong
var path = resolver.FindPath(person, person.Address, null); // Throws
// Correct
var path = resolver.FindPath(person, person.Address, "Street");
```
--------------------------------
### Blazilla Architecture Overview
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/README.md
This diagram illustrates the flow of data and events within Blazilla during form validation.
```text
User interacts with form
↓
EditContext fires events
↓
FluentValidator listens to events
↓
FluentValidator resolves validator from DI
↓
FluentValidator builds validation context
↓
FluentValidator executes validation
↓
PathResolver maps field paths
↓
Validation errors added to message store
↓
UI updates with validation messages
```
--------------------------------
### Single Assembly Scan for Validators
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/ServiceCollectionExtensions.md
Shows the efficient way to register all validators from a single assembly using one method call.
```csharp
services.AddValidatorsFromAssemblyContaining();
```
```csharp
services.AddValidatorsFromAssemblyContaining();
services.AddValidatorsFromAssemblyContaining();
```
--------------------------------
### Define Rule Sets for Validation
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Organize validation rules into named sets ('Create', 'Update') for selective execution. Default rules are always applied.
```csharp
public class PersonValidator : AbstractValidator
{
public PersonValidator()
{
// Default rules (always executed)
RuleFor(p => p.FirstName).NotEmpty();
// Rules in specific rule sets
RuleSet("Create", () =>
{
RuleFor(p => p.EmailAddress)
.NotEmpty()
.EmailAddress();
});
RuleSet("Update", () =>
{
RuleFor(p => p.LastName).NotEmpty();
});
}
}
```
--------------------------------
### Array Fast Path Optimization
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/EnumerableExtensions.md
Implements direct O(1) access for arrays using Array.GetValue(). Handles cases where the index is out of bounds by returning null.
```csharp
if (source is Array array)
return index < array.Length ? array.GetValue(index) : null;
```
--------------------------------
### Create Validators for Collection Items and Parent
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/integration-patterns.md
Implement validators for individual items within a collection and for the parent object that contains the collection.
```csharp
public class PhoneNumberValidator : AbstractValidator
{
public PhoneNumberValidator()
{
RuleFor(p => p.Type)
.NotEmpty().WithMessage("Phone type is required");
RuleFor(p => p.Number)
.NotEmpty().Matches(@"^\d{3}-\d{3}-\d{4}$")
.WithMessage("Phone must be in format XXX-XXX-XXXX");
}
}
public class PersonValidator : AbstractValidator
{
public PersonValidator()
{
RuleFor(p => p.Name)
.NotEmpty().WithMessage("Name is required");
RuleForEach(p => p.PhoneNumbers)
.SetValidator(new PhoneNumberValidator());
}
}
```
--------------------------------
### Update Using Statement from Blazored.FluentValidation to Blazilla
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Replace the old using statement with the new one for Blazilla in your C# files.
```csharp
using Blazored.FluentValidation;
```
```csharp
using Blazilla;
```
--------------------------------
### Avoiding ArgumentNullException in PathResolver.FindField (null path)
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Demonstrates how to correctly call PathResolver.FindField by providing a non-null path string. Passing null for the path will throw an ArgumentNullException.
```csharp
var person = new Person();
// Wrong
var field = PathResolver.FindField(person, null); // Throws
// Correct
var field = PathResolver.FindField(person, "Address.Street");
```
--------------------------------
### Avoiding ArgumentNullException in PathResolver.FindField (null rootObject)
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Demonstrates how to correctly call PathResolver.FindField by ensuring the root object is not null. Passing null for rootObject will throw an ArgumentNullException.
```csharp
// Wrong
var field = PathResolver.FindField(null, "Address.Street"); // Throws
// Correct
var person = new Person();
var field = PathResolver.FindField(person, "Address.Street");
```
--------------------------------
### Find Path with Target Instance and Property
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathResolver.md
Finds the property path to a specific property on a target instance within an object graph. Throws ArgumentNullException if any parameter is null.
```csharp
public string? FindPath(
object rootObject,
object targetInstance,
string targetProperty)
```
```csharp
var person = new Person
{
FirstName = "Jane",
Address = new Address { City = "Seattle" }
};
var resolver = new PathResolver();
var path = resolver.FindPath(person, person.Address, "City");
// Returns "Address.City"
```
--------------------------------
### Using Assembly Scanning for Validators
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/errors.md
Configure Blazilla to scan assemblies for validators. This automatically registers all found validators in the DI container.
```csharp
using Blazilla.Extensions;
builder.Services.AddValidatorsFromAssemblyContaining();
```
--------------------------------
### Create a Person Model
Source: https://github.com/loresoft/blazilla/blob/main/README.md
Define a C# class to represent the data for your form. This model will be used with FluentValidation.
```csharp
public class Person
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
public int Age { get; set; }
public string? EmailAddress { get; set; }
}
```
--------------------------------
### Configure Logging Level
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/configuration.md
Set the logging level for Blazilla.FluentValidator in appsettings.json. 'Debug' provides detailed validation event information.
```json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Blazilla.FluentValidator": "Debug"
}
}
}
```
--------------------------------
### Efficient Access for Custom Enumerables
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/EnumerableExtensions.md
Compares inefficient repeated access to a custom enumerable with efficient conversion to a list first. Use ToList() for repeated access to custom enumerables.
```csharp
// Inefficient - O(n) per access
var custom = GetCustomEnumerable();
var item1 = custom.ElementAtOrDefault(0);
var item2 = custom.ElementAtOrDefault(1);
// Efficient - O(n) once, then O(1)
var list = custom.ToList();
var item1 = list.ElementAtOrDefault(0);
var item2 = list.ElementAtOrDefault(1);
```
--------------------------------
### Configure Singleton Service Lifetime for Validators
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/configuration.md
Register validators as Singletons for optimal performance, as they are stateless and thread-safe.
```csharp
builder.Services.AddSingleton, PersonValidator>();
```
```csharp
// Avoid - unnecessary overhead
builder.Services.AddTransient, PersonValidator>();
builder.Services.AddScoped, PersonValidator>();
```
--------------------------------
### Person and Address Models
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/integration-patterns.md
Define the C# classes for the person and their nested address. These models represent the data structure to be validated.
```csharp
public class PersonModel
{
public string Name { get; set; }
public AddressModel Address { get; set; }
}
public class AddressModel
{
public string Street { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
}
```
--------------------------------
### PushIndex
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/api-reference/PathStack.md
Pushes an index value onto the stack, marking it for bracket enclosure.
```APIDOC
## PushIndex(T)
### Description
Pushes an index value onto the stack and marks it as an indexer to be enclosed in brackets.
### Method
`PushIndex`
### Parameters
#### Path Parameters
- **index** (T) - Required - The index value. Converted to string using `ToString()`. Null values become an empty string.
### Type Parameters
- **T**: The type of the index value (typically `int`, `string`, or other types with meaningful string representations).
### Request Example
```csharp
var pathStack = new PathStack();
pathStack.PushProperty("Items");
pathStack.PushIndex(0);
pathStack.PushProperty("Name");
// Stack represents: "Items[0].Name"
```
```
--------------------------------
### Manual Validator Registration for AOT
Source: https://github.com/loresoft/blazilla/blob/main/_autodocs/configuration.md
For Ahead-of-Time (AOT) compilation, use manual registration of validators instead of assembly scanning to prevent compilation failures.
```csharp
// Bad for AOT
builder.Services.AddValidatorsFromAssemblyContaining();
// Good for AOT
builder.Services.AddSingleton, PersonValidator>();
```