### 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>(); ```