59 lines
2.6 KiB
C#
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;
|
|
}
|
|
}
|