Migrating all validation to use HTMX and endpoints instead of WASM/Websocket connections

This commit is contained in:
2026-04-13 18:40:17 +05:00
parent d1f0967a0c
commit b323862e03
24 changed files with 1203 additions and 188 deletions
@@ -0,0 +1,55 @@
using System.Globalization;
using System.Reflection;
using Microsoft.AspNetCore.Http;
namespace Enciphered.Blazor.UIComponents.Validation;
public static class FormModelBinder
{
public static TModel Bind<TModel>(IFormCollection form) where TModel : new()
{
var model = new TModel();
var props = typeof(TModel).GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanWrite);
foreach (var prop in props)
{
var key = form.Keys.FirstOrDefault(k =>
string.Equals(k, prop.Name, StringComparison.OrdinalIgnoreCase));
if (key is null) continue;
var raw = form[key].ToString();
var value = ConvertValue(raw, prop.PropertyType);
if (value is not null)
prop.SetValue(model, value);
}
return model;
}
private static object? ConvertValue(string raw, Type target)
{
var underlying = Nullable.GetUnderlyingType(target);
var isNullable = underlying is not null;
var type = underlying ?? target;
if (string.IsNullOrWhiteSpace(raw))
return isNullable ? null : (type == typeof(string) ? "" : null);
if (type == typeof(string)) return raw;
if (type == typeof(int)) return int.TryParse(raw, out var i) ? i : null;
if (type == typeof(long)) return long.TryParse(raw, out var l) ? l : null;
if (type == typeof(double)) return double.TryParse(raw, CultureInfo.InvariantCulture, out var d) ? d : null;
if (type == typeof(decimal)) return decimal.TryParse(raw, CultureInfo.InvariantCulture, out var m) ? m : null;
if (type == typeof(float)) return float.TryParse(raw, CultureInfo.InvariantCulture, out var f) ? f : null;
if (type == typeof(bool)) return bool.TryParse(raw, out var b) ? b : raw == "on" || raw == "1";
if (type == typeof(DateTime)) return DateTime.TryParse(raw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : null;
if (type == typeof(DateOnly)) return DateOnly.TryParse(raw, CultureInfo.InvariantCulture, DateTimeStyles.None, out var d2) ? d2 : null;
if (type == typeof(TimeOnly)) return TimeOnly.TryParse(raw, CultureInfo.InvariantCulture, out var t) ? t : null;
if (type == typeof(Guid)) return Guid.TryParse(raw, out var g) ? g : null;
if (type.IsEnum) return Enum.TryParse(type, raw, ignoreCase: true, out var e) ? e : null;
return null;
}
}