Files
BusinessMgr-2019/SaBusMgrCoreWeb/Web/Middleware/SbmModelBinder.cs
T
2024-06-13 14:32:44 +01:00

113 lines
4.3 KiB
C#

using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Text.RegularExpressions;
// Ignore obsolete warning on ComplexTypeModelBinder.
#pragma warning disable 0618
namespace Sarand.BusinessMgr.Net.Core.Web.Middleware
{
//=======================================================================
/// <summary>
/// Maps a browser request to a data object. Default class provides a base implementation of a model binder.
/// <para>- Overridden to trim whitespace from input values.</para>
/// </summary>
public class SbmModelBinder : ComplexTypeModelBinder
{
//-------------------------------------------------------------------
// Construction.
public SbmModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) :
base(propertyBinders, loggerFactory)
{
}
//-------------------------------------------------------------------
/// <summary>
/// Creates the model with one (or more) injected service parameters.
/// </summary>
protected override object CreateModel(ModelBindingContext bindingContext)
{
var services = bindingContext.HttpContext.RequestServices;
var modelType = bindingContext.ModelType;
var ctors = modelType.GetConstructors();
foreach (var ctor in ctors)
{
var paramTypes = ctor.GetParameters().Select(p => p.ParameterType).ToList();
var parameters = paramTypes.Select(p => services.GetService(p)).ToArray();
if (parameters.All(p => p != null))
{
var model = ctor.Invoke(parameters);
return model;
}
}
return null;
}
//-------------------------------------------------------------------
/// <summary>
/// Intercept String properties and trim whitespace.
/// </summary>
protected override void SetProperty(ModelBindingContext bindingContext, string modelName, ModelMetadata propertyMetadata, ModelBindingResult result)
{
//if (SbmSystem.DebugMode) Logger.Debug($"{SysUtil.Fn} Form property " + modelName + ": '" + result.Model.ToString() + ".");
object originalValue = result.Model;
// Anything that looks like a password will be left as is.
bool password = modelName.ContainsCI("Password");
// Exclude properties that retain leading/trailing whitespace.
if (result.Model is string)
{
if (!password)
{
string value = result.Model as string;
// Trim leading and trailing whitespace.
value = StringUtil.TrimAll(value);
// Check for multi-line.
if (value.Contains('\n'))
{
// Simplify line delimiters.
value = Regex.Replace(value, "\\r\\n", "\n");
// Remove white space in front of newlines.
value = Regex.Replace(value, "\\s+\\n", "\n");
// Remove multiple newlines.
value = Regex.Replace(value, "\\n+", "\n");
}
// Email addresses must be lowercase to ensure match to encrypted data.
if (modelName.EqualsCI("EmailAddress") || modelName.EqualsCI("AccountEmailAddress"))
value = value.ToLower();
// Uppercase selected values.
if (modelName.EqualsCI("Postcode") || modelName.EqualsCI("AccountPostcode") || modelName.EqualsCI("RegisteredAddressPostcode"))
value = value.ToUpper();
// Assign resulting value.
result = ModelBindingResult.Success(value);
}
}
// Log property details.
if (result.Model != null && SbmSystem.DebugMode &&
// Ignore passwords.
!password &&
// Ignore items that correspond with objects in the model rather than values.
!result.Model.ToString().Equals(result.Model.GetType().FullName) &&
// Ignore form files.
!result.Model.ToString().ContainsCI("Microsoft.AspNetCore.Http.IFormFile"))
SaLogger.Debug(SysUtil.Fn + " Form property " + modelName + ": '" + result.Model.ToString() + "'." + (originalValue != null && !originalValue.Equals(result.Model) ? " Original value: '" + originalValue.ToString() + "'" : ""));
base.SetProperty(bindingContext, modelName, propertyMetadata, result);
}
//-------------------------------------------------------------------
}
//=======================================================================
}