Files
Enciphered.Blazor.UIComponents/Enciphered.Blazor.UIComponents/Forms/Validation/FormModelBinder.cs
T

59 lines
2.6 KiB
C#

using System.Globalization;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http;
namespace Enciphered.Blazor.UIComponents.Validation;
public static class FormModelBinder
{
public static TModel Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TModel>(IFormCollection form) where TModel : new()
{
var model = new TModel();
PropertyInfo[] props = typeof(TModel).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in props)
{
if (!prop.CanWrite) continue;
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;
}
}