Skip to content

Commit

Permalink
Add StronglyTyped, LambdaExtensions and JsonModelBinder
Browse files Browse the repository at this point in the history
  • Loading branch information
VahidN committed May 9, 2024
1 parent afba210 commit 777704b
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/DNTCommon.Web.Core/DNTCommon.Web.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>DNTCommon.Web.Core provides common scenarios' solutions for ASP.NET Core applications.</Description>
<VersionPrefix>5.0.0</VersionPrefix>
<VersionPrefix>5.1.0</VersionPrefix>
<Authors>Vahid Nasiri</Authors>
<TargetFrameworks>net8.0;net7.0;net6.0;</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down Expand Up @@ -58,7 +58,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.9.28">
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.10.48">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand All @@ -70,7 +70,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.24.0.89429">
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.25.0.90414">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand All @@ -81,7 +81,7 @@
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2"/>
<PackageReference Include="DNTPersianUtils.Core" Version="6.3.0"/>
<PackageReference Include="MailKit" Version="4.5.0"/>
<PackageReference Include="HtmlAgilityPack" Version="1.11.60"/>
<PackageReference Include="HtmlAgilityPack" Version="1.11.61"/>
<PackageReference Include="IPAddressRange" Version="6.0.0"/>
<PackageReference Include="SkiaSharp" Version="2.88.8"/>
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.8"/>
Expand Down
25 changes: 25 additions & 0 deletions src/DNTCommon.Web.Core/MiscUtils/LambdaExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Linq.Expressions;

namespace DNTCommon.Web.Core;

/// <summary>
/// Expression Helpers
/// </summary>
public static class LambdaExtensions
{
/// <summary>
/// Get the actual return type of expr
/// </summary>
public static Type? GetObjectType<TEntity>(this Expression<Func<TEntity, object?>>? 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;
}
}
23 changes: 23 additions & 0 deletions src/DNTCommon.Web.Core/MiscUtils/PathUtils.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
using System.Text.RegularExpressions;
using DNTPersianUtils.Core;

namespace DNTCommon.Web.Core;

/// <summary>
/// Path Utils
/// </summary>
public static class PathUtils
{
private static readonly TimeSpan MatchTimeout = TimeSpan.FromSeconds(3);

/// <summary>
/// Find files by their extensions
/// </summary>
Expand Down Expand Up @@ -44,4 +49,22 @@ public static void DeleteFiles(this string path, params string[] extensions)
file.Delete();
}
}

/// <summary>
/// Removes InvalidFileNameChars and InvalidPathChars from the given input
/// </summary>
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()!;
}
}
46 changes: 46 additions & 0 deletions src/DNTCommon.Web.Core/MiscUtils/StronglyTyped.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Linq.Expressions;

namespace DNTCommon.Web.Core;

/// <summary>
/// Get the string name and type of property or field.
/// </summary>
public class StronglyTyped : ExpressionVisitor
{
private Stack<string>? _stack;

/// <summary>
/// Get the string name and type of property or field.
/// </summary>
public static string PropertyPath<TEntity>(Expression<Func<TEntity, object?>>? expression, string separator)
=> expression is null ? string.Empty : new StronglyTyped().Name(expression, separator);

/// <summary>
/// Get the string name and type of property or field.
/// </summary>
public string Path(Expression expression, string separator)
{
_stack = new Stack<string>();
Visit(expression);

return _stack.Aggregate((s1, s2) => $"{s1}{separator}{s2}");
}

/// <summary>
/// Visits the children of the System.Linq.Expressions.MemberExpression.
/// </summary>
protected override Expression VisitMember(MemberExpression node)
{
ArgumentNullException.ThrowIfNull(node);

_stack?.Push(node.Member.Name);

return base.VisitMember(node);
}

/// <summary>
/// Get the string name and type of property or field.
/// </summary>
public string Name<TEntity>(Expression<Func<TEntity, object?>> expression, string separator)
=> Path(expression, separator);
}
43 changes: 43 additions & 0 deletions src/DNTCommon.Web.Core/ModelBinders/JsonModelBinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Text.Json;
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace DNTCommon.Web.Core;

/// <summary>
/// Json ModelBinder
/// </summary>
public class JsonModelBinder : IModelBinder
{
/// <summary>
/// Attempts to bind a model.
/// </summary>
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;
}
}

0 comments on commit 777704b

Please sign in to comment.