diff --git a/src/DNTCommon.Web.Core/DNTCommon.Web.Core.csproj b/src/DNTCommon.Web.Core/DNTCommon.Web.Core.csproj index f1d4db7..dd8e8cd 100644 --- a/src/DNTCommon.Web.Core/DNTCommon.Web.Core.csproj +++ b/src/DNTCommon.Web.Core/DNTCommon.Web.Core.csproj @@ -1,7 +1,7 @@ DNTCommon.Web.Core provides common scenarios' solutions for ASP.NET Core applications. - 5.0.0 + 5.1.0 Vahid Nasiri net8.0;net7.0;net6.0; true @@ -58,7 +58,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -70,7 +70,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -81,7 +81,7 @@ - + diff --git a/src/DNTCommon.Web.Core/MiscUtils/LambdaExtensions.cs b/src/DNTCommon.Web.Core/MiscUtils/LambdaExtensions.cs new file mode 100644 index 0000000..f191902 --- /dev/null +++ b/src/DNTCommon.Web.Core/MiscUtils/LambdaExtensions.cs @@ -0,0 +1,25 @@ +using System.Linq.Expressions; + +namespace DNTCommon.Web.Core; + +/// +/// Expression Helpers +/// +public static class LambdaExtensions +{ + /// + /// Get the actual return type of expr + /// + public static Type? GetObjectType(this Expression>? expression) + { + if (expression is null) + { + return null; + } + + return expression.Body.NodeType is ExpressionType.Convert or ExpressionType.ConvertChecked && + expression.Body is UnaryExpression unary + ? unary.Operand.Type + : expression.Body.Type; + } +} \ No newline at end of file diff --git a/src/DNTCommon.Web.Core/MiscUtils/PathUtils.cs b/src/DNTCommon.Web.Core/MiscUtils/PathUtils.cs index f52da29..c0b2600 100644 --- a/src/DNTCommon.Web.Core/MiscUtils/PathUtils.cs +++ b/src/DNTCommon.Web.Core/MiscUtils/PathUtils.cs @@ -1,3 +1,6 @@ +using System.Text.RegularExpressions; +using DNTPersianUtils.Core; + namespace DNTCommon.Web.Core; /// @@ -5,6 +8,8 @@ namespace DNTCommon.Web.Core; /// public static class PathUtils { + private static readonly TimeSpan MatchTimeout = TimeSpan.FromSeconds(3); + /// /// Find files by their extensions /// @@ -44,4 +49,22 @@ public static void DeleteFiles(this string path, params string[] extensions) file.Delete(); } } + + /// + /// Removes InvalidFileNameChars and InvalidPathChars from the given input + /// + public static string RemoveIllegalCharactersFromFileName(this string fileName) + { + if (string.IsNullOrWhiteSpace(fileName)) + { + return string.Empty; + } + + var regexSearch = $"{new string(Path.GetInvalidFileNameChars())}{new string(Path.GetInvalidPathChars())}"; + + var r = new Regex($"[{Regex.Escape(regexSearch)}]", RegexOptions.Compiled | RegexOptions.IgnoreCase, + MatchTimeout); + + return r.Replace(fileName, ".").GetPostSlug()!; + } } \ No newline at end of file diff --git a/src/DNTCommon.Web.Core/MiscUtils/StronglyTyped.cs b/src/DNTCommon.Web.Core/MiscUtils/StronglyTyped.cs new file mode 100644 index 0000000..6837d09 --- /dev/null +++ b/src/DNTCommon.Web.Core/MiscUtils/StronglyTyped.cs @@ -0,0 +1,46 @@ +using System.Linq.Expressions; + +namespace DNTCommon.Web.Core; + +/// +/// Get the string name and type of property or field. +/// +public class StronglyTyped : ExpressionVisitor +{ + private Stack? _stack; + + /// + /// Get the string name and type of property or field. + /// + public static string PropertyPath(Expression>? expression, string separator) + => expression is null ? string.Empty : new StronglyTyped().Name(expression, separator); + + /// + /// Get the string name and type of property or field. + /// + public string Path(Expression expression, string separator) + { + _stack = new Stack(); + Visit(expression); + + return _stack.Aggregate((s1, s2) => $"{s1}{separator}{s2}"); + } + + /// + /// Visits the children of the System.Linq.Expressions.MemberExpression. + /// + protected override Expression VisitMember(MemberExpression node) + { + ArgumentNullException.ThrowIfNull(node); + + _stack?.Push(node.Member.Name); + + return base.VisitMember(node); + } + + /// + /// Get the string name and type of property or field. + /// + public string Name(Expression> expression, string separator) + => Path(expression, separator); +} \ No newline at end of file diff --git a/src/DNTCommon.Web.Core/ModelBinders/JsonModelBinder.cs b/src/DNTCommon.Web.Core/ModelBinders/JsonModelBinder.cs new file mode 100644 index 0000000..8f47c04 --- /dev/null +++ b/src/DNTCommon.Web.Core/ModelBinders/JsonModelBinder.cs @@ -0,0 +1,43 @@ +using System.Text.Json; +using Microsoft.AspNetCore.Mvc.ModelBinding; + +namespace DNTCommon.Web.Core; + +/// +/// Json ModelBinder +/// +public class JsonModelBinder : IModelBinder +{ + /// + /// Attempts to bind a model. + /// + public Task BindModelAsync(ModelBindingContext bindingContext) + { + ArgumentNullException.ThrowIfNull(bindingContext); + + var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); + + if (valueProviderResult != ValueProviderResult.None) + { + bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); + + var valueAsString = valueProviderResult.FirstValue; + + if (string.IsNullOrWhiteSpace(valueAsString)) + { + return Task.CompletedTask; + } + + var result = JsonSerializer.Deserialize(valueAsString, bindingContext.ModelType); + + if (result is not null) + { + bindingContext.Result = ModelBindingResult.Success(result); + + return Task.CompletedTask; + } + } + + return Task.CompletedTask; + } +} \ No newline at end of file