using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Utils; using Saxonite.Net.Core.Web.Base.App; using Saxonite.Net.Standard.Base.App; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace Saxonite.Net.Core.Web.Base.Middleware { //======================================================================= /// /// Maps a browser request to a data object. Default class provides a base implementation of a model binder. /// Overridden to trim whitespace from input values. /// public class SaxModelBinder : ComplexTypeModelBinder { //------------------------------------------------------------------- // Construction. public SaxModelBinder(IDictionary propertyBinders, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base(propertyBinders, loggerFactory) { } //------------------------------------------------------------------- /// /// Creates the model with one (or more) injected service parameters. /// 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; } //------------------------------------------------------------------- /// /// Intercept String properties and trim whitespace. /// protected override void SetProperty(ModelBindingContext bindingContext, string modelName, ModelMetadata propertyMetadata, ModelBindingResult result) { //if (SaxSystem.DebugMode) Logger.Debug(fn + " Form property " + modelName + ": '" + result.Model.ToString() + "."); object originalValue = result.Model; // Exclude properties that retain leading/trailing whitespace. if (result.Model is string) { if (!modelName.ContainsCI("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 && SaxSystem.DebugMode && // 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); } //------------------------------------------------------------------- } //======================================================================= }