diff --git a/demo/AspNetCore/AspNetCore.csproj b/demo/AspNetCore/AspNetCore.csproj
index 7b6a27f..15c3bb0 100644
--- a/demo/AspNetCore/AspNetCore.csproj
+++ b/demo/AspNetCore/AspNetCore.csproj
@@ -34,7 +34,26 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Common.resx
+
+
+
+
+
+ PublicResXFileCodeGenerator
+ Common.Designer.cs
+
diff --git a/demo/AspNetCore/Controllers/EmployeeController.cs b/demo/AspNetCore/Controllers/EmployeeController.cs
index 02f2fd8..46a19e6 100644
--- a/demo/AspNetCore/Controllers/EmployeeController.cs
+++ b/demo/AspNetCore/Controllers/EmployeeController.cs
@@ -14,7 +14,7 @@ public ActionResult Index()
// GET: Employee/Create
public ActionResult Create()
{
- return View();
+ return View(new Employee());
}
// POST: Employee/Create
@@ -29,5 +29,24 @@ public ActionResult Create(Employee employee)
return View(employee);
}
+
+ // GET: Employee/Create
+ public ActionResult CreateWithResx()
+ {
+ return View(new EmployeeWithResx());
+ }
+
+ // POST: Employee/Create
+ [HttpPost]
+ [ValidateAntiForgeryToken]
+ public ActionResult CreateWithResx(EmployeeWithResx employee)
+ {
+ if (ModelState.IsValid)
+ {
+ return View();
+ }
+
+ return View(employee);
+ }
}
}
\ No newline at end of file
diff --git a/demo/AspNetCore/Models/Employee.cs b/demo/AspNetCore/Models/Employee.cs
index 6372491..e625ae9 100644
--- a/demo/AspNetCore/Models/Employee.cs
+++ b/demo/AspNetCore/Models/Employee.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
+using AspNetCore.Models;
using Microsoft.AspNetCore.Http;
using TanvirArjel.CustomValidation.AspNetCore.Attributes;
using TanvirArjel.CustomValidation.Attributes;
@@ -70,6 +71,8 @@ public class Employee : IValidatableObject
[RequiredIf(nameof(IsPhoneRequired), ComparisonType.Equal, true)]
public string Phone { get; set; }
+ public PreviousJobExperience[] PreviousJobs { get; set; } = new PreviousJobExperience[2];
+
public IEnumerable Validate(ValidationContext validationContext)
{
List validationResults = new List();
diff --git a/demo/AspNetCore/Models/EmployeeWithResx.cs b/demo/AspNetCore/Models/EmployeeWithResx.cs
new file mode 100644
index 0000000..19bcd0c
--- /dev/null
+++ b/demo/AspNetCore/Models/EmployeeWithResx.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using AspNetCore.Models;
+using AspNetCore.Resources;
+using Microsoft.AspNetCore.Http;
+using TanvirArjel.CustomValidation.AspNetCore.Attributes;
+using TanvirArjel.CustomValidation.Attributes;
+
+namespace AspNetCore.CustomValidation.Demo.Models;
+
+public class EmployeeWithResx : IValidatableObject
+{
+ ////[DisplayName("Name")]
+ ////[FixedLength(5, ErrorMessage = "{0} should be exactly {1} characters long.")]
+ ////[TextEditorRequired]
+ [Required]
+ [MinLength(5)]
+ [AspNetCore.MyCustomAttributes.FooAtrribute]
+ public string FirstName { get; set; }
+
+ [RequiredIf(nameof(FirstName), ComparisonType.Equal, "Tanvir", ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "RequiredError")]
+ public string LastName { get; set; }
+
+ [Required]
+ [Range(1000, 9999)]
+ [Display(Name = "Starting Year")]
+ public int? StartingYear { get; set; }
+
+ [Required]
+ [Range(1000, 9999)]
+ [CompareTo(nameof(StartingYear), ComparisonType.GreaterThanOrEqual, ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "GreaterThanOrEqualError")]
+ [Display(Name = "Ending Year")]
+ public int? EndingYear { get; set; }
+
+ ////[DataType(DataType.Date)]
+ ////[DisplayName("Date Of Birth")]
+ [Required]
+ [MinAge(15, 11, 3, ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "MinAgeError")]
+ [MaxAge(20, 11, 3, ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "MaxAgeError")]
+ public DateTime DateOfBirth { get; set; }
+
+ ////[MinDate(2019, 1, 1, ErrorMessage = "{0} should be minimun 2019 January 1.")] // 2019 January 1
+ ////[MaxDate(2019, 10, 1, ErrorMessage = "{0} cannot be greater than {1}.")] // 2019 October 1
+ ////[CompareTo(nameof(DateOfBirth), ComparisonType.GreaterThan)]
+ [DisplayName("Joining Date")]
+ ////[RequiredIf(nameof(DateOfBirth), ComparisonType.Equal, "01-May-2020")]
+ public DateTime? JoiningDate { get; set; }
+
+ [Display(Name = "First Number")]
+ [RequiredIf(nameof(SecondNumber), ComparisonType.Equal, null, ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "RequiredError")]
+ public int? FirstNumber { get; set; }
+
+ ////[RequiredIf(nameof(FirstNumber), ComparisonType.Equal, null)]
+ [Display(Name = "Second Number")]
+ [CompareTo(nameof(FirstNumber), ComparisonType.GreaterThan, ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "GreaterThanError")]
+ public int? SecondNumber { get; set; }
+
+ ////[FileType(new FileType[] { FileType.Mp4, FileType.Mp3 }, ErrorMessage = "{0} should be in {1} formats.")]
+ ////[FileMinSize(10000, ErrorMessage = "{0} should be at least {1}.")]
+ [FileType(FileType.Jpeg, ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "FileTypeError")]
+ [FileMinSize(1024, ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "FileMinSizeError")]
+ public IFormFile Photo { get; set; }
+
+ public TimeSpan? EntryTime { get; set; }
+
+ [RequiredIf(nameof(EntryTime), ComparisonType.GreaterThan, "10:00", ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "RequiredError")]
+ public TimeSpan? OutTime { get; set; }
+
+ public bool IsPhoneRequired { get; set; }
+
+ [RequiredIf(nameof(IsPhoneRequired), ComparisonType.Equal, true, ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "RequiredError")]
+ public string Phone { get; set; }
+
+ public PreviousJobExperience[] PreviousJobs { get; set; } = new PreviousJobExperience[2];
+
+ public IEnumerable Validate(ValidationContext validationContext)
+ {
+ List validationResults = new List();
+
+ // FileOptions fileOptions = new FileOptions()
+ // {
+ // FileTypes = new FileType[] {FileType.Jpeg,FileType.Jpg},
+ // MinSize = 124,
+ // MaxSize = Convert.ToInt32(AppSettings.GetValue("DemoSettings:MaxFileSize"))
+ // };
+
+ // ValidationResult fileValidationResult = validationContext.ValidateFile(nameof(Photo), fileOptions);
+ // validationResults.Add(fileValidationResult);
+
+ // ValidationResult minAgeValidationResult = validationContext.ValidateMinAge(nameof(DateOfBirth), 10, 0, 0);
+ // validationResults.Add(minAgeValidationResult);
+ return validationResults;
+ }
+}
diff --git a/demo/AspNetCore/Models/PreviousJobExperience.cs b/demo/AspNetCore/Models/PreviousJobExperience.cs
new file mode 100644
index 0000000..c11ef8b
--- /dev/null
+++ b/demo/AspNetCore/Models/PreviousJobExperience.cs
@@ -0,0 +1,19 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using TanvirArjel.CustomValidation.Attributes;
+
+namespace AspNetCore.Models
+{
+ public class PreviousJobExperience
+ {
+ [DataType(DataType.Date)]
+ public DateTime? StartDate { get; set; }
+
+ [DataType(DataType.Date)]
+ [CompareTo(nameof(StartDate), ComparisonType.GreaterThan)]
+ public DateTime? EndDate { get; set; }
+
+ [RequiredIf(nameof(StartDate), ComparisonType.NotEqual, null)]
+ public string JobName { get; set; }
+ }
+}
diff --git a/demo/AspNetCore/Resources/Common.Designer.cs b/demo/AspNetCore/Resources/Common.Designer.cs
new file mode 100644
index 0000000..dab3bc7
--- /dev/null
+++ b/demo/AspNetCore/Resources/Common.Designer.cs
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace AspNetCore.Resources {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ public class Common {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Common() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AspNetCore.Resources.Common", typeof(Common).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0} should be at least {1}.
+ ///
+ public static string FileMinSizeError {
+ get {
+ return ResourceManager.GetString("FileMinSizeError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The {0} should be in {1} formats.
+ ///
+ public static string FileTypeError {
+ get {
+ return ResourceManager.GetString("FileTypeError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The {0} should be greater than {1}.
+ ///
+ public static string GreaterThanError {
+ get {
+ return ResourceManager.GetString("GreaterThanError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The {0} should be greater than or equal {1}.
+ ///
+ public static string GreaterThanOrEqualError {
+ get {
+ return ResourceManager.GetString("GreaterThanOrEqualError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The {0} cannot be smaller than {1}.
+ ///
+ public static string MaxAgeError {
+ get {
+ return ResourceManager.GetString("MaxAgeError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The {0} cannot be larger than {1}.
+ ///
+ public static string MinAgeError {
+ get {
+ return ResourceManager.GetString("MinAgeError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The {0} field is required.
+ ///
+ public static string RequiredError {
+ get {
+ return ResourceManager.GetString("RequiredError", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/demo/AspNetCore/Resources/Common.resx b/demo/AspNetCore/Resources/Common.resx
new file mode 100644
index 0000000..89fa71a
--- /dev/null
+++ b/demo/AspNetCore/Resources/Common.resx
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ The {0} should be greater than {1}
+
+
+ The {0} should be greater than or equal {1}
+
+
+ The {0} cannot be larger than {1}
+
+
+ The {0} cannot be smaller than {1}
+
+
+ The {0} field is required
+
+
+ The {0} should be in {1} formats
+
+
+ {0} should be at least {1}
+
+
\ No newline at end of file
diff --git a/demo/AspNetCore/Resources/Views/Employee/Create.fr.resx b/demo/AspNetCore/Resources/Views/Employee/Create.fr.resx
index 5bcf8f3..fc7f776 100644
--- a/demo/AspNetCore/Resources/Views/Employee/Create.fr.resx
+++ b/demo/AspNetCore/Resources/Views/Employee/Create.fr.resx
@@ -126,4 +126,7 @@
Employée
+
+
+
\ No newline at end of file
diff --git a/demo/AspNetCore/Resources/Views/Employee/Create.resx b/demo/AspNetCore/Resources/Views/Employee/Create.resx
new file mode 100644
index 0000000..8663cce
--- /dev/null
+++ b/demo/AspNetCore/Resources/Views/Employee/Create.resx
@@ -0,0 +1,17 @@
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/AspNetCore/Views/Employee/Create.cshtml b/demo/AspNetCore/Views/Employee/Create.cshtml
index e019f41..6812f15 100644
--- a/demo/AspNetCore/Views/Employee/Create.cshtml
+++ b/demo/AspNetCore/Views/Employee/Create.cshtml
@@ -99,6 +99,26 @@
+
+ @for (var i = 0; i < Model.PreviousJobs.Length; i++)
+ {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
diff --git a/demo/AspNetCore/Views/Employee/CreateWithResx.cshtml b/demo/AspNetCore/Views/Employee/CreateWithResx.cshtml
new file mode 100644
index 0000000..df87ef5
--- /dev/null
+++ b/demo/AspNetCore/Views/Employee/CreateWithResx.cshtml
@@ -0,0 +1,166 @@
+@using Microsoft.AspNetCore.Mvc.Localization
+@model AspNetCore.CustomValidation.Demo.Models.EmployeeWithResx
+@inject IViewLocalizer Localizer
+@{
+ ViewData["Title"] = Localizer["Create"];
+}
+
+
+@Localizer["Create"]
+
+@Localizer["EmployeeWithResx"]
+
+
+
+
+
+@section Scripts {
+
+ @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
+
+
+
+
+}
diff --git a/demo/AspNetCore/Views/Shared/_Layout.cshtml b/demo/AspNetCore/Views/Shared/_Layout.cshtml
index 9b73b5a..1c138b5 100644
--- a/demo/AspNetCore/Views/Shared/_Layout.cshtml
+++ b/demo/AspNetCore/Views/Shared/_Layout.cshtml
@@ -34,6 +34,11 @@
@Localizer["Employee"]
+
+
+ @Localizer["EmployeeWithResx"]
+
+
diff --git a/demo/AspNetCore/wwwroot/lib/tanvirarjel-custom-validation-unobtrusive/tanvirarjel.customvalidation.unobtrusive.js b/demo/AspNetCore/wwwroot/lib/tanvirarjel-custom-validation-unobtrusive/tanvirarjel.customvalidation.unobtrusive.js
index afeb572..2dcf111 100644
--- a/demo/AspNetCore/wwwroot/lib/tanvirarjel-custom-validation-unobtrusive/tanvirarjel.customvalidation.unobtrusive.js
+++ b/demo/AspNetCore/wwwroot/lib/tanvirarjel-custom-validation-unobtrusive/tanvirarjel.customvalidation.unobtrusive.js
@@ -56,6 +56,17 @@
}
}
+ function getInputName(otherPropertyName, elementName) {
+ let modelPrefix = elementName.substr(0, elementName.lastIndexOf(".") + 1);
+
+ if (otherPropertyName.indexOf("*.") === 0) {
+ otherPropertyName = otherPropertyName.replace("*.", modelPrefix);
+ }
+
+ // As mentioned on http://api.jquery.com/category/selectors/
+ return otherPropertyName.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
+ }
+
// valid date validation
$.validator.addMethod("valid-date-format", function (value, element, params) {
if (value) {
@@ -121,11 +132,7 @@
// max age validation
$.validator.addMethod("maxage", function (value, element, params) {
if (value) {
- let maxAgeDateTime = new Date();
-
- maxAgeDateTime.setFullYear(maxAgeDateTime.getFullYear() - params.years);
- maxAgeDateTime.setMonth(maxAgeDateTime.getMonth() - params.months);
- maxAgeDateTime.setDate(maxAgeDateTime.getDate() - params.days);
+ let maxAgeDateTime = new Date(params.maxagedatetime);
const inputDate = getDateValue(value);
return inputDate >= maxAgeDateTime;
@@ -134,7 +141,7 @@
return true;
});
- $.validator.unobtrusive.adapters.add("maxage", ['years', 'months', 'days'], function (options) {
+ $.validator.unobtrusive.adapters.add("maxage", ['maxagedatetime'], function (options) {
options.rules.maxage = options.params;
options.messages["maxage"] = options.message;
});
@@ -142,10 +149,7 @@
// min age validation
$.validator.addMethod("minage", function (value, element, params) {
if (value) {
- let minAgeDateTime = new Date();
- minAgeDateTime.setFullYear(minAgeDateTime.getFullYear() - params.years);
- minAgeDateTime.setMonth(minAgeDateTime.getMonth() - params.months);
- minAgeDateTime.setDate(minAgeDateTime.getDate() - params.days);
+ let minAgeDateTime = new Date(params.minagedatetime);
const inputDate = getDateValue(value);
return minAgeDateTime >= inputDate;
@@ -154,7 +158,7 @@
return true;
});
- $.validator.unobtrusive.adapters.add("minage", ['years', 'months', 'days'], function (options) {
+ $.validator.unobtrusive.adapters.add("minage", ['minagedatetime'], function (options) {
options.rules.minage = options.params;
options.messages["minage"] = options.message;
});
@@ -211,7 +215,7 @@
$.validator.addMethod("input-type-compare", function (value, element, params) {
var inputPropertyType = $(element).prop('type');
var comparePropertyName = params["property"];
- var compareProperty = $(element).closest('form').find('[name="' + comparePropertyName + '"]');
+ var compareProperty = $(element).closest('form').find('[name="' + getInputName(comparePropertyName, element.name) + '"]');
var comparePropertyType = compareProperty.prop('type');
return inputPropertyType === comparePropertyType;
@@ -230,7 +234,7 @@
const inputPropertyType = $(element).prop('type');
const comparePropertyName = params.property;
- const compareProperty = $(element).closest('form').find('[name="' + comparePropertyName + '"]');
+ const compareProperty = $(element).closest('form').find('[name="' + getInputName(comparePropertyName, element.name) + '"]');
const comparePropertyType = compareProperty.prop('type');
const comparePropertyValue = compareProperty.val();
@@ -278,7 +282,7 @@
const inputPropertyType = $(element).prop('type');
const comparePropertyName = params.property;
- const compareProperty = $(element).closest('form').find('[name="' + comparePropertyName + '"]');
+ const compareProperty = $(element).closest('form').find('[name="' + getInputName(comparePropertyName, element.name) + '"]');
const comparePropertyType = compareProperty.prop('type');
const comparePropertyValue = compareProperty.val();
@@ -324,7 +328,7 @@
let inputPropertyType = $(element).prop('type');
const comparePropertyName = params.property;
- const compareProperty = $(element).closest('form').find('[name="' + comparePropertyName + '"]');
+ const compareProperty = $(element).closest('form').find('[name="' + getInputName(comparePropertyName, element.name) + '"]');
const comparePropertyType = compareProperty.prop('type');
const comparePropertyValue = compareProperty.val();
@@ -372,7 +376,7 @@
let inputPropertyType = $(element).prop('type');
const comparePropertyName = params.property;
- const compareProperty = $(element).closest('form').find('[name="' + comparePropertyName + '"]');
+ const compareProperty = $(element).closest('form').find('[name="' + getInputName(comparePropertyName, element.name) + '"]');
const comparePropertyType = compareProperty.prop('type');
const comparePropertyValue = compareProperty.val();
@@ -418,7 +422,7 @@
const inputPropertyType = $(element).prop('type');
const comparePropertyName = params.property;
- const compareProperty = $(element).closest('form').find('[name="' + comparePropertyName + '"]');
+ const compareProperty = $(element).closest('form').find('[name="' + getInputName(comparePropertyName, element.name) + '"]');
const comparePropertyType = compareProperty.prop('type');
const comparePropertyValue = compareProperty.val();
@@ -464,7 +468,7 @@
const inputPropertyType = $(element).prop('type');
const comparePropertyName = params.property;
- const compareProperty = $(element).closest('form').find('[name="' + comparePropertyName + '"]');
+ const compareProperty = $(element).closest('form').find('[name="' + getInputName(comparePropertyName, element.name) + '"]');
const comparePropertyType = compareProperty.prop('type');
const comparePropertyValue = compareProperty.val();
@@ -565,16 +569,17 @@
const otherPropertyName = params['other-property'];
const comparisonType = params['comparison-type'];
const otherPropertyType = params['other-property-type'];
- let otherPropertyValue = params['other-property-value'];
+ let otherPropertyValue = params['other-property-value'];
+ let inputName = getInputName(otherPropertyName, element.name);
- const otherPropertyElement = $(element).closest('form').find('[name="' + otherPropertyName + '"]');
+ const otherPropertyElement = $(element).closest('form').find('[name="' + inputName + '"]');
const otherPropertyInputType = otherPropertyElement.attr('type');
let otherPropertyCurrentValue = null;
if (otherPropertyInputType == "checkbox" || otherPropertyInputType == "radio") {
- var control = $("[name$='" + otherPropertyName + "']:checked");
+ var control = $("[name$='" + inputName + "']:checked");
otherPropertyCurrentValue = control.val();
} else {
otherPropertyCurrentValue = otherPropertyElement.val();
diff --git a/src/AspNetCore.CustomValidation/Attributes/CompareToAttribute.cs b/src/AspNetCore.CustomValidation/Attributes/CompareToAttribute.cs
new file mode 100644
index 0000000..8d70efb
--- /dev/null
+++ b/src/AspNetCore.CustomValidation/Attributes/CompareToAttribute.cs
@@ -0,0 +1,417 @@
+using AspNetCore.CustomValidation.Extensions;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
+
+namespace AspNetCore.CustomValidation.Attributes
+{
+ ///
+ /// This is used to compare the decorated property value against the another property value of the same object.
+ ///
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
+ public class CompareToAttribute : ValidationAttribute, IClientModelValidator
+ {
+ private string ComparePropertyName { get; }
+ private ComparisonType ComparisonType { get; }
+
+ ///
+ /// This constructor takes the and values.
+ ///
+ /// Name of the property which against the comparison will be done.
+ /// The .
+ public CompareToAttribute(string comparePropertyName, ComparisonType comparisonType)
+ {
+ ComparePropertyName = comparePropertyName;
+ ComparisonType = comparisonType;
+ }
+
+ protected override ValidationResult IsValid(object value, ValidationContext validationContext)
+ {
+ if (validationContext == null)
+ {
+ throw new ArgumentNullException(nameof(validationContext));
+ }
+
+ PropertyInfo compareProperty = validationContext.ObjectType.GetProperty(ComparePropertyName);
+
+ if (compareProperty == null)
+ {
+ throw new ArgumentException($"The object does not contain any property with name '{ComparePropertyName}'");
+ }
+
+ Type comparePropertyType = compareProperty.PropertyType;
+
+ if (comparePropertyType == null)
+ {
+ throw new ArgumentNullException($"The type of {ComparePropertyName} is null");
+ }
+
+ var comparePropertyValue = compareProperty.GetValue(validationContext.ObjectInstance, null);
+
+ if (value == null || comparePropertyValue == null)
+ {
+ return ValidationResult.Success;
+ }
+
+ PropertyInfo propertyInfo = validationContext.ObjectType.GetProperty(validationContext.MemberName);
+
+ if (propertyInfo == null)
+ {
+ throw new ArgumentException($"The object does not contain any property with name '{validationContext.MemberName}'");
+ }
+
+ Type memberType = propertyInfo.PropertyType;
+
+ if (memberType == null)
+ {
+ throw new ArgumentException($"The type of {validationContext.MemberName} is null.");
+ }
+
+ if (memberType == comparePropertyType)
+ {
+ var validationResult = TriggerValueComparison();
+ return validationResult;
+ }
+ else
+ {
+ if (value.IsNumber() && comparePropertyValue.IsNumber())
+ {
+ var validationResult = TriggerValueComparison();
+ return validationResult;
+ }
+ else if (value is DateTime && comparePropertyValue is DateTime)
+ {
+ var validationResult = TriggerValueComparison();
+ return validationResult;
+ }
+ else if (value is TimeSpan && comparePropertyValue is TimeSpan)
+ {
+ var validationResult = TriggerValueComparison();
+ return validationResult;
+ }
+ else
+ {
+ throw new ArgumentException($"The type of {validationContext.MemberName} is not comparable to type of {ComparePropertyName}");
+ }
+ }
+
+ ValidationResult TriggerValueComparison()
+ {
+ var propertyDisplayName = validationContext.DisplayName;
+ var comparePropertyDisplayAttribute = compareProperty.GetCustomAttributes(typeof(DisplayAttribute), true).FirstOrDefault() as DisplayAttribute;
+ var comparePropertyDisplayName = comparePropertyDisplayAttribute?.GetName() ?? ComparePropertyName;
+
+ if (ComparisonType == ComparisonType.Equal)
+ {
+ var errorMessage = GetFormattedErrorMessage(EqualityErrorMessage, propertyDisplayName, comparePropertyDisplayName);
+
+ if (value.IsNumber() && comparePropertyValue.IsNumber())
+ {
+ if (Convert.ToDecimal(value, CultureInfo.InvariantCulture) != Convert.ToDecimal(comparePropertyValue, CultureInfo.InvariantCulture))
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is DateTime memberValue)
+ {
+ if (memberValue != (DateTime)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is TimeSpan timeSpanValue)
+ {
+ if (timeSpanValue != (TimeSpan)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is string)
+ {
+ if (value.ToString() != comparePropertyValue.ToString())
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ }
+
+ if (ComparisonType == ComparisonType.NotEqual)
+ {
+ var errorMessage = GetFormattedErrorMessage(NotEqualityErrorMessage, propertyDisplayName, comparePropertyDisplayName);
+
+ if (value.IsNumber() && comparePropertyValue.IsNumber())
+ {
+ if (Convert.ToDecimal(value, CultureInfo.InvariantCulture) == Convert.ToDecimal(comparePropertyValue, CultureInfo.InvariantCulture))
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is DateTime memberValue)
+ {
+ if (memberValue == (DateTime)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is TimeSpan timeSpanValue)
+ {
+ if (timeSpanValue == (TimeSpan)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is string)
+ {
+ if (value.ToString() == comparePropertyValue.ToString())
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ }
+
+ if (ComparisonType == ComparisonType.GreaterThan)
+ {
+ var errorMessage = GetFormattedErrorMessage(GreaterThanErrorMessage, propertyDisplayName, comparePropertyDisplayName);
+
+ if (value.IsNumber())
+ {
+ if (Convert.ToDecimal(value, CultureInfo.InvariantCulture) <= Convert.ToDecimal(comparePropertyValue, CultureInfo.InvariantCulture))
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value.IsDateTime())
+ {
+ if ((DateTime)value <= (DateTime)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value.IsTimeSpan())
+ {
+ if ((TimeSpan)value <= (TimeSpan)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is string)
+ {
+ if (value.ToString().Length <= comparePropertyValue.ToString().Length)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+ }
+
+ if (ComparisonType == ComparisonType.GreaterThanOrEqual)
+ {
+ var errorMessage = GetFormattedErrorMessage(GreaterThanOrEqualErrorMessage, propertyDisplayName, comparePropertyDisplayName);
+
+ if (value.IsNumber())
+ {
+ if (Convert.ToDecimal(value, CultureInfo.InvariantCulture) < Convert.ToDecimal(comparePropertyValue, CultureInfo.InvariantCulture))
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value.IsDateTime())
+ {
+ if ((DateTime)value < (DateTime)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value.IsTimeSpan())
+ {
+ if ((TimeSpan)value < (TimeSpan)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is string)
+ {
+ if (value.ToString().Length < comparePropertyValue.ToString().Length)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+ }
+
+ if (ComparisonType == ComparisonType.SmallerThan)
+ {
+ var errorMessage = GetFormattedErrorMessage(SmallerThanErrorMessage, propertyDisplayName, comparePropertyDisplayName);
+
+ if (value.IsNumber())
+ {
+ if (Convert.ToDecimal(value, CultureInfo.InvariantCulture) >= Convert.ToDecimal(comparePropertyValue, CultureInfo.InvariantCulture))
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value.IsDateTime())
+ {
+ if ((DateTime)value >= (DateTime)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value.IsTimeSpan())
+ {
+ if ((TimeSpan)value >= (TimeSpan)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is string)
+ {
+ if (value.ToString().Length >= comparePropertyValue.ToString().Length)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+ }
+
+ if (ComparisonType == ComparisonType.SmallerThanOrEqual)
+ {
+ var errorMessage = GetFormattedErrorMessage(SmallerThanOrEqualErrorMessage, propertyDisplayName, comparePropertyDisplayName);
+
+ if (value.IsNumber())
+ {
+ if (Convert.ToDecimal(value, CultureInfo.InvariantCulture) > Convert.ToDecimal(comparePropertyValue, CultureInfo.InvariantCulture))
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value.IsDateTime())
+ {
+ if ((DateTime)value > (DateTime)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value.IsTimeSpan())
+ {
+ if ((TimeSpan)value > (TimeSpan)comparePropertyValue)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+
+ if (value is string)
+ {
+ if (value.ToString().Length > comparePropertyValue.ToString().Length)
+ {
+ return new ValidationResult(errorMessage);
+ }
+ }
+ }
+
+ return ValidationResult.Success;
+ }
+ }
+
+ private string EqualityErrorMessage => ErrorMessage ?? "The {0} is not equal to {1}.";
+ private string NotEqualityErrorMessage => ErrorMessage ?? "The {0} can not be equal to {1}.";
+ private string GreaterThanErrorMessage => ErrorMessage ?? "The {0} should be greater than {1}.";
+ private string GreaterThanOrEqualErrorMessage => ErrorMessage ?? "The {0} should be greater than or equal {1}.";
+ private string SmallerThanErrorMessage => ErrorMessage ?? "The {0} should be smaller than {1}.";
+ private string SmallerThanOrEqualErrorMessage => ErrorMessage ?? "The {0} should be smaller than or equal {1}.";
+
+ public void AddValidation(ClientModelValidationContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ var propertyName = context.ModelMetadata.GetDisplayName();
+
+ AddAttribute(context.Attributes, "data-val", "true");
+ AddAttribute(context.Attributes, "data-val-input-type-compare", $"{propertyName} is not comparable to {ComparePropertyName}");
+ AddAttribute(context.Attributes, "data-val-input-type-compare-property", ComparePropertyName);
+
+ if (ComparisonType == ComparisonType.Equal)
+ {
+ AddAttribute(context.Attributes, "data-val-comparison-equal", GetFormattedErrorMessage(EqualityErrorMessage, propertyName, ComparePropertyName));
+ AddAttribute(context.Attributes, "data-val-comparison-equal-property", ComparePropertyName);
+ }
+
+ if (ComparisonType == ComparisonType.NotEqual)
+ {
+ AddAttribute(context.Attributes, "data-val-comparison-not-equal", GetFormattedErrorMessage(NotEqualityErrorMessage, propertyName, ComparePropertyName));
+ AddAttribute(context.Attributes, "data-val-comparison-not-equal-property", ComparePropertyName);
+ }
+
+ if (ComparisonType == ComparisonType.GreaterThan)
+ {
+ AddAttribute(context.Attributes, "data-val-comparison-greater-than", GetFormattedErrorMessage(GreaterThanErrorMessage, propertyName, ComparePropertyName));
+ AddAttribute(context.Attributes, "data-val-comparison-greater-than-property", ComparePropertyName);
+ }
+
+ if (ComparisonType == ComparisonType.GreaterThanOrEqual)
+ {
+ AddAttribute(context.Attributes, "data-val-comparison-greater-than-or-equal", GetFormattedErrorMessage(GreaterThanOrEqualErrorMessage, propertyName, ComparePropertyName));
+ AddAttribute(context.Attributes, "data-val-comparison-greater-than-or-equal-property", ComparePropertyName);
+ }
+
+ if (ComparisonType == ComparisonType.SmallerThan)
+ {
+ AddAttribute(context.Attributes, "data-val-comparison-smaller-than", GetFormattedErrorMessage(SmallerThanErrorMessage, propertyName, ComparePropertyName));
+ AddAttribute(context.Attributes, "data-val-comparison-smaller-than-property", ComparePropertyName);
+ }
+
+ if (ComparisonType == ComparisonType.SmallerThanOrEqual)
+ {
+ AddAttribute(context.Attributes, "data-val-comparison-smaller-than-or-equal", GetFormattedErrorMessage(SmallerThanOrEqualErrorMessage, propertyName, ComparePropertyName));
+ AddAttribute(context.Attributes, "data-val-comparison-smaller-than-or-equal-property", ComparePropertyName);
+ }
+ }
+
+ private void AddAttribute(IDictionary attributes, string key, string value)
+ {
+ if (!attributes.ContainsKey(key))
+ {
+ attributes.Add(key, value);
+ }
+ }
+
+ private string GetFormattedErrorMessage(string errorMessage, string propertyName, string comparePropertyName)
+ {
+ return string.Format(CultureInfo.InvariantCulture, errorMessage, propertyName, comparePropertyName);
+ }
+ }
+
+
+ public enum ComparisonType
+ {
+ Equal,
+ NotEqual,
+ GreaterThan,
+ GreaterThanOrEqual,
+ SmallerThan,
+ SmallerThanOrEqual
+ }
+}
diff --git a/src/AspNetCore.CustomValidation/Extensions/ObjectExtensions.cs b/src/AspNetCore.CustomValidation/Extensions/ObjectExtensions.cs
new file mode 100644
index 0000000..8484bb2
--- /dev/null
+++ b/src/AspNetCore.CustomValidation/Extensions/ObjectExtensions.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace AspNetCore.CustomValidation.Extensions
+{
+ internal static class ObjectExtensions
+ {
+ internal static bool IsNumber(this object value)
+ {
+ return value is sbyte
+ || value is byte
+ || value is short
+ || value is ushort
+ || value is int
+ || value is uint
+ || value is long
+ || value is ulong
+ || value is float
+ || value is double
+ || value is decimal;
+ }
+
+ internal static bool IsDateTime(this object value)
+ {
+ return value is DateTime;
+ }
+
+ internal static bool IsTimeSpan(this object value)
+ {
+ return value is TimeSpan;
+ }
+ }
+}
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/AdapterProviders/TanvirArjelAttributeAdapterProvider.cs b/src/TanvirArjel.CustomValidation.AspNetCore/AdapterProviders/TanvirArjelAttributeAdapterProvider.cs
index 801c2b8..6d3b30d 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/AdapterProviders/TanvirArjelAttributeAdapterProvider.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/AdapterProviders/TanvirArjelAttributeAdapterProvider.cs
@@ -50,8 +50,14 @@ public virtual IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribu
return new MinDateAttributeAdapter(minDateAttribute, stringLocalizer);
case RequiredIfAttribute requiredIfAttribute:
return new RequiredIfAttributeAdapter(requiredIfAttribute, stringLocalizer);
+ case TextEditorAttribute textEditorAttribute:
+ return new TextEditorAttributeAdapter(textEditorAttribute, stringLocalizer);
case TextEditorRequiredAttribute textEditorRequiredAttribute:
return new TextEditorRequiredAttributeAdapter(textEditorRequiredAttribute, stringLocalizer);
+ case TextEditorMaxLengthAttribute textEditorMaxLengthAttribute:
+ return new TextEditorMaxLengthAttributeAdapter(textEditorMaxLengthAttribute, stringLocalizer);
+ case TextEditorMinLengthAttribute textEditorMinLengthAttribute:
+ return new TextEditorMinLengthAttributeAdapter(textEditorMinLengthAttribute, stringLocalizer);
default:
return _baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
}
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/CompareToAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/CompareToAttributeAdapter.cs
index e7cff1c..acc35f6 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/CompareToAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/CompareToAttributeAdapter.cs
@@ -16,7 +16,7 @@ namespace TanvirArjel.CustomValidation.AspNetCore.Adapters
internal class CompareToAttributeAdapter : AttributeAdapterBase
{
public CompareToAttributeAdapter(CompareToAttribute attribute, IStringLocalizer stringLocalizer)
- : base(attribute, stringLocalizer)
+ : base(new CompareToAttributeWrapper(attribute), stringLocalizer)
{
}
@@ -33,6 +33,9 @@ public override void AddValidation(ClientModelValidationContext context)
AddAttribute(context.Attributes, "data-val", "true");
AddAttribute(context.Attributes, "data-val-input-type-compare", $"{propertyDisplayName} is not comparable to {comparePropertyName}");
+
+ comparePropertyName = "*." + comparePropertyName;
+
AddAttribute(context.Attributes, "data-val-input-type-compare-property", comparePropertyName);
if (comparisonType == ComparisonType.Equal)
@@ -83,6 +86,8 @@ public override string GetErrorMessage(ModelValidationContextBase validationCont
string comparePropertyDisplayName = validationContext.ModelMetadata.ContainerMetadata.Properties
.Single(p => p.PropertyName == Attribute.ComparePropertyName).GetDisplayName();
+ ((CompareToAttributeWrapper)Attribute).ComparePropertyDisplayName = comparePropertyDisplayName;
+
return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, comparePropertyDisplayName);
}
@@ -94,9 +99,32 @@ private static void AddAttribute(IDictionary attributes, string
}
}
- private static string GetFormattedErrorMessage(string errorMessage, string propertyName, string comparePropertyName)
+ // The attribute wrapper is needed to override the FormatErrorMessage method
+ // See https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.DataAnnotations/src/CompareAttributeAdapter.cs
+ private sealed class CompareToAttributeWrapper : CompareToAttribute
{
- return string.Format(CultureInfo.InvariantCulture, errorMessage, propertyName, comparePropertyName);
+ public CompareToAttributeWrapper(CompareToAttribute attribute)
+ : base(attribute.ComparePropertyName, attribute.ComparisonType)
+ {
+ if (!string.IsNullOrEmpty(attribute.ErrorMessage) ||
+ !string.IsNullOrEmpty(attribute.ErrorMessageResourceName) ||
+ attribute.ErrorMessageResourceType != null)
+ {
+ ErrorMessage = attribute.ErrorMessage;
+ ErrorMessageResourceName = attribute.ErrorMessageResourceName;
+ ErrorMessageResourceType = attribute.ErrorMessageResourceType;
+ }
+ }
+
+ ///
+ /// Display name of the property which against the comparison will be done.
+ ///
+ public string ComparePropertyDisplayName { get; set; }
+
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, ComparePropertyDisplayName ?? ComparePropertyName);
+ }
}
}
}
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileMaxSizeAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileMaxSizeAttributeAdapter.cs
index 5305c2c..343842c 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileMaxSizeAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileMaxSizeAttributeAdapter.cs
@@ -41,9 +41,8 @@ public override string GetErrorMessage(ModelValidationContextBase validationCont
}
string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
- int maxSize = Attribute.MaxSize;
- string maxSizeAndUnit = maxSize >= 1024 ? Math.Round(maxSize / 1024M, 2) + " MB" : maxSize + " KB";
- return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, maxSizeAndUnit);
+
+ return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.MaxSizeAndUnit);
}
private static void AddAttribute(IDictionary attributes, string key, string value)
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileMinSizeAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileMinSizeAttributeAdapter.cs
index 080f084..fbe658b 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileMinSizeAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileMinSizeAttributeAdapter.cs
@@ -41,9 +41,8 @@ public override string GetErrorMessage(ModelValidationContextBase validationCont
}
string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
- int minSize = Attribute.MinSize;
- string minSizeAndUnit = minSize >= 1024 ? Math.Round(minSize / 1024M, 2) + " MB" : minSize + " KB";
- return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, minSizeAndUnit);
+
+ return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.MinSizeAndUnit);
}
private static void AddAttribute(IDictionary attributes, string key, string value)
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileTypeAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileTypeAttributeAdapter.cs
index 3ce313f..296d863 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileTypeAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/FileTypeAttributeAdapter.cs
@@ -42,9 +42,8 @@ public override string GetErrorMessage(ModelValidationContextBase validationCont
}
string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
- string[] validFileTypeNames = Attribute.FileTypes.Select(ft => ft.ToString("G")).ToArray();
- string validFileTypeNamesString = string.Join(",", validFileTypeNames);
- return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, validFileTypeNamesString);
+
+ return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.ValidFileTypeNamesString);
}
private static void AddAttribute(IDictionary attributes, string key, string value)
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MaxAgeAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MaxAgeAttributeAdapter.cs
index 633858a..d52a6dc 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MaxAgeAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MaxAgeAttributeAdapter.cs
@@ -31,22 +31,28 @@ public override void AddValidation(ClientModelValidationContext context)
AddAttribute(context.Attributes, "data-val", "true");
- AddAttribute(context.Attributes, "data-val-valid-date-format", "The input date/datetime format is not valid! Please prefer: '01-Jan-2019' format.");
- AddAttribute(context.Attributes, "data-val-currenttime", $"{propertyDisplayName} can not be greater than today's date.");
- AddAttribute(context.Attributes, "data-val-maxage", errorMessage);
+ AddAttribute(context.Attributes, "data-val-valid-date-format",
+ "The input date/datetime format is not valid! Please prefer: '01-Jan-2019' format.");
+
+ AddAttribute(context.Attributes, "data-val-currenttime",
+ $"{propertyDisplayName} can not be greater than today's date.");
- string years = Attribute.Years.ToString(CultureInfo.InvariantCulture);
- string months = Attribute.Months.ToString(CultureInfo.InvariantCulture);
- string days = Attribute.Days.ToString(CultureInfo.InvariantCulture);
+ AddAttribute(context.Attributes, "data-val-maxage", errorMessage);
- AddAttribute(context.Attributes, "data-val-maxage-years", years);
- AddAttribute(context.Attributes, "data-val-maxage-months", months);
- AddAttribute(context.Attributes, "data-val-maxage-days", days);
+ string maxAgeDateTime = Attribute.MaxAgeDateTime.ToString("dd-MMM-yyyy", CultureInfo.InvariantCulture);
+ AddAttribute(context.Attributes, "data-val-maxage-maxagedatetime", maxAgeDateTime);
}
public override string GetErrorMessage(ModelValidationContextBase validationContext)
{
- return GetErrorMessage(validationContext.ModelMetadata, Attribute.Years, Attribute.Months, Attribute.Days);
+ if (validationContext == null)
+ {
+ throw new ArgumentNullException(nameof(validationContext));
+ }
+
+ string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
+
+ return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.MaxAgeDateTime.ToString(Attribute.ErrorMessageMaxAgeDateTimeFormat, CultureInfo.CurrentCulture));
}
private static void AddAttribute(IDictionary attributes, string key, string value)
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MaxDateAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MaxDateAttributeAdapter.cs
index fc9a00f..faa6cd6 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MaxDateAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MaxDateAttributeAdapter.cs
@@ -43,7 +43,7 @@ public override string GetErrorMessage(ModelValidationContextBase validationCont
}
string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
- return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.MaxDate);
+ return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.MaxDate.ToString(Attribute.ErrorMessageMaxDateFormat, CultureInfo.CurrentCulture));
}
private static void AddAttribute(IDictionary attributes, string key, string value)
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MinAgeAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MinAgeAttributeAdapter.cs
index 8208dcd..92cd452 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MinAgeAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MinAgeAttributeAdapter.cs
@@ -35,18 +35,20 @@ public override void AddValidation(ClientModelValidationContext context)
AddAttribute(context.Attributes, "data-val-minage", errorMessage);
- string years = Attribute.Years.ToString(CultureInfo.InvariantCulture);
- string months = Attribute.Months.ToString(CultureInfo.InvariantCulture);
- string days = Attribute.Days.ToString(CultureInfo.InvariantCulture);
-
- AddAttribute(context.Attributes, "data-val-minage-years", years);
- AddAttribute(context.Attributes, "data-val-minage-months", months);
- AddAttribute(context.Attributes, "data-val-minage-days", days);
+ string minAgeDateTime = Attribute.MinAgeDateTime.ToString("dd-MMM-yyyy", CultureInfo.InvariantCulture);
+ AddAttribute(context.Attributes, "data-val-minage-minagedatetime", minAgeDateTime);
}
public override string GetErrorMessage(ModelValidationContextBase validationContext)
{
- return GetErrorMessage(validationContext.ModelMetadata, Attribute.Years, Attribute.Months, Attribute.Years);
+ if (validationContext == null)
+ {
+ throw new ArgumentNullException(nameof(validationContext));
+ }
+
+ string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
+
+ return GetErrorMessage(validationContext.ModelMetadata,propertyDisplayName, Attribute.MinAgeDateTime.ToString(Attribute.ErrorMessageMinAgeDateTimeFormat, CultureInfo.CurrentCulture));
}
private static void AddAttribute(IDictionary attributes, string key, string value)
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MinDateAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MinDateAttributeAdapter.cs
index c27716c..a36ad06 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MinDateAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/MinDateAttributeAdapter.cs
@@ -44,7 +44,7 @@ public override string GetErrorMessage(ModelValidationContextBase validationCont
}
string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
- return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.MinDate);
+ return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.MinDate.ToString(Attribute.ErrorMessageMinDateFormat, CultureInfo.CurrentCulture));
}
private static void AddAttribute(IDictionary attributes, string key, string value)
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/RequiredIfAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/RequiredIfAttributeAdapter.cs
index 60b1a2d..2b0752e 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/RequiredIfAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/RequiredIfAttributeAdapter.cs
@@ -57,7 +57,7 @@ public override void AddValidation(ClientModelValidationContext context)
}
AddAttribute(context.Attributes, "data-val", "true");
- AddAttribute(context.Attributes, "data-val-requiredif-other-property", Attribute.OtherPropertyName);
+ AddAttribute(context.Attributes, "data-val-requiredif-other-property", "*." + Attribute.OtherPropertyName);
AddAttribute(context.Attributes, "data-val-requiredif-comparison-type", Attribute.ComparisonType.ToString());
AddAttribute(context.Attributes, "data-val-requiredif-other-property-value", Attribute.OtherPropertyValue?.ToString() ?? string.Empty);
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorAttributeAdapter.cs
new file mode 100644
index 0000000..7f09e04
--- /dev/null
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorAttributeAdapter.cs
@@ -0,0 +1,76 @@
+//
+// Copyright (c) TanvirArjel. All rights reserved.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Microsoft.AspNetCore.Mvc.DataAnnotations;
+using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
+using Microsoft.Extensions.Localization;
+using TanvirArjel.CustomValidation.Attributes;
+
+namespace TanvirArjel.CustomValidation.AspNetCore.Adapters
+{
+ internal class TextEditorAttributeAdapter : AttributeAdapterBase
+ {
+ private IStringLocalizer _stringLocalizer;
+
+ public TextEditorAttributeAdapter(TextEditorAttribute attribute, IStringLocalizer stringLocalizer)
+ : base(attribute, stringLocalizer)
+ {
+ _stringLocalizer = stringLocalizer;
+ }
+
+ public override void AddValidation(ClientModelValidationContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ AddAttribute(context.Attributes, "data-val", "true");
+ AddAttribute(context.Attributes, "data-val-texteditor-required", GetErrorMessage(context));
+
+ string propertyDisplayName = context.ModelMetadata.GetDisplayName();
+
+ if (Attribute.MinLength > 0)
+ {
+ string minLengthErrorMessage = _stringLocalizer[Attribute.MinLengthErrorMessage];
+ string formattedMinLengthErrorMessage = string.Format(CultureInfo.InvariantCulture, minLengthErrorMessage, propertyDisplayName, Attribute.MinLength);
+
+ AddAttribute(context.Attributes, "data-val-texteditor-minlength", formattedMinLengthErrorMessage);
+ AddAttribute(context.Attributes, "data-val-texteditor-minlength-value", Attribute.MinLength.ToString(CultureInfo.InvariantCulture));
+ }
+
+ if (Attribute.MaxLength > 0)
+ {
+ string maxLengthErrorMessage = _stringLocalizer[Attribute.MaxLengthErrorMessage];
+ string formattedMaxLengthErrorMessage = string.Format(CultureInfo.InvariantCulture, maxLengthErrorMessage, propertyDisplayName, Attribute.MaxLength);
+
+ AddAttribute(context.Attributes, "data-val-texteditor-maxlength", formattedMaxLengthErrorMessage);
+ AddAttribute(context.Attributes, "data-val-texteditor-maxlength-value", Attribute.MaxLength.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ public override string GetErrorMessage(ModelValidationContextBase validationContext)
+ {
+ if (validationContext == null)
+ {
+ throw new ArgumentNullException(nameof(validationContext));
+ }
+
+ string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
+
+ return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName);
+ }
+
+ private static void AddAttribute(IDictionary attributes, string key, string value)
+ {
+ if (!attributes.ContainsKey(key))
+ {
+ attributes.Add(key, value);
+ }
+ }
+ }
+}
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorMaxLengthAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorMaxLengthAttributeAdapter.cs
new file mode 100644
index 0000000..2e33bb5
--- /dev/null
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorMaxLengthAttributeAdapter.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Microsoft.AspNetCore.Mvc.DataAnnotations;
+using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
+using Microsoft.Extensions.Localization;
+using TanvirArjel.CustomValidation.Attributes;
+
+namespace TanvirArjel.CustomValidation.AspNetCore.Adapters
+{
+ internal class TextEditorMaxLengthAttributeAdapter : AttributeAdapterBase
+ {
+ public TextEditorMaxLengthAttributeAdapter(TextEditorMaxLengthAttribute attribute, IStringLocalizer stringLocalizer)
+ : base(attribute, stringLocalizer)
+ {
+ }
+
+ public override void AddValidation(ClientModelValidationContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ AddAttribute(context.Attributes, "data-val", "true");
+
+ if (Attribute.MaxLength > 0)
+ {
+ AddAttribute(context.Attributes, "data-val-texteditor-maxlength", GetErrorMessage(context));
+ AddAttribute(context.Attributes, "data-val-texteditor-maxlength-value", Attribute.MaxLength.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ public override string GetErrorMessage(ModelValidationContextBase validationContext)
+ {
+ if (validationContext == null)
+ {
+ throw new ArgumentNullException(nameof(validationContext));
+ }
+
+ string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
+
+ return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.MaxLength);
+ }
+
+ private static void AddAttribute(IDictionary attributes, string key, string value)
+ {
+ if (!attributes.ContainsKey(key))
+ {
+ attributes.Add(key, value);
+ }
+ }
+ }
+}
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorMinLengthAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorMinLengthAttributeAdapter.cs
new file mode 100644
index 0000000..cc3a0be
--- /dev/null
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorMinLengthAttributeAdapter.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Microsoft.AspNetCore.Mvc.DataAnnotations;
+using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
+using Microsoft.Extensions.Localization;
+using TanvirArjel.CustomValidation.Attributes;
+
+namespace TanvirArjel.CustomValidation.AspNetCore.Adapters
+{
+ internal class TextEditorMinLengthAttributeAdapter : AttributeAdapterBase
+ {
+ public TextEditorMinLengthAttributeAdapter(TextEditorMinLengthAttribute attribute, IStringLocalizer stringLocalizer)
+ : base(attribute, stringLocalizer)
+ {
+ }
+
+ public override void AddValidation(ClientModelValidationContext context)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ AddAttribute(context.Attributes, "data-val", "true");
+
+ if (Attribute.MinLength > 0)
+ {
+ AddAttribute(context.Attributes, "data-val-texteditor-minlength", GetErrorMessage(context));
+ AddAttribute(context.Attributes, "data-val-texteditor-minlength-value", Attribute.MinLength.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ public override string GetErrorMessage(ModelValidationContextBase validationContext)
+ {
+ if (validationContext == null)
+ {
+ throw new ArgumentNullException(nameof(validationContext));
+ }
+
+ string propertyDisplayName = validationContext.ModelMetadata.GetDisplayName();
+
+ return GetErrorMessage(validationContext.ModelMetadata, propertyDisplayName, Attribute.MinLength);
+ }
+
+ private static void AddAttribute(IDictionary attributes, string key, string value)
+ {
+ if (!attributes.ContainsKey(key))
+ {
+ attributes.Add(key, value);
+ }
+ }
+ }
+}
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorRequiredAttributeAdapter.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorRequiredAttributeAdapter.cs
index d503f28..11a7da1 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorRequiredAttributeAdapter.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Adapters/TextEditorRequiredAttributeAdapter.cs
@@ -1,10 +1,5 @@
-//
-// Copyright (c) TanvirArjel. All rights reserved.
-//
-
-using System;
+using System;
using System.Collections.Generic;
-using System.Globalization;
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Localization;
@@ -31,26 +26,6 @@ public override void AddValidation(ClientModelValidationContext context)
AddAttribute(context.Attributes, "data-val", "true");
AddAttribute(context.Attributes, "data-val-texteditor-required", GetErrorMessage(context));
-
- string propertyDisplayName = context.ModelMetadata.GetDisplayName();
-
- if (Attribute.MinLength > 0)
- {
- string minLengthErrorMessage = _stringLocalizer[Attribute.MinLengthErrorMessage];
- string formattedMinLengthErrorMessage = string.Format(CultureInfo.InvariantCulture, minLengthErrorMessage, propertyDisplayName, Attribute.MinLength);
-
- AddAttribute(context.Attributes, "data-val-texteditor-minlength", formattedMinLengthErrorMessage);
- AddAttribute(context.Attributes, "data-val-texteditor-minlength-value", Attribute.MinLength.ToString(CultureInfo.InvariantCulture));
- }
-
- if (Attribute.MaxLength > 0)
- {
- string maxLengthErrorMessage = _stringLocalizer[Attribute.MaxLengthErrorMessage];
- string formattedMaxLengthErrorMessage = string.Format(CultureInfo.InvariantCulture, maxLengthErrorMessage, propertyDisplayName, Attribute.MaxLength);
-
- AddAttribute(context.Attributes, "data-val-texteditor-maxlength", formattedMaxLengthErrorMessage);
- AddAttribute(context.Attributes, "data-val-texteditor-maxlength-value", Attribute.MaxLength.ToString(CultureInfo.InvariantCulture));
- }
}
public override string GetErrorMessage(ModelValidationContextBase validationContext)
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileMaxSizeAttribute.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileMaxSizeAttribute.cs
index 9d8c7fb..57adf33 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileMaxSizeAttribute.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileMaxSizeAttribute.cs
@@ -20,9 +20,9 @@ public sealed class FileMaxSizeAttribute : ValidationAttribute
///
/// Allowed of the file in KB.
public FileMaxSizeAttribute(int maxSize)
+ : base("{0} should be not more than {1}.")
{
MaxSize = maxSize;
- ErrorMessage = ErrorMessage ?? "{0} should be not more than {1}.";
}
///
@@ -33,7 +33,12 @@ public FileMaxSizeAttribute(int maxSize)
///
/// Get allowed of the file with appropriate unit.
///
- private string MaxSizeAndUnit => MaxSize >= 1024 ? Math.Round(MaxSize / 1024M, 2) + " MB" : MaxSize + " KB";
+ internal string MaxSizeAndUnit => MaxSize >= 1024 ? Math.Round(MaxSize / 1024M, 2) + " MB" : MaxSize + " KB";
+
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MaxSizeAndUnit);
+ }
///
/// To check whether the input is larger than the specified size.
@@ -72,8 +77,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
if (MaxSize > 0 && fileLengthInKByte > MaxSize)
{
- string formattedErrorMessage = string.Format(CultureInfo.InvariantCulture, ErrorMessage, validationContext.DisplayName, MaxSizeAndUnit);
- return new ValidationResult(formattedErrorMessage);
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
else
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileMinSizeAttribute.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileMinSizeAttribute.cs
index 9575b97..bc64f1a 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileMinSizeAttribute.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileMinSizeAttribute.cs
@@ -20,9 +20,9 @@ public sealed class FileMinSizeAttribute : ValidationAttribute
///
/// Allowed of the file in KB.
public FileMinSizeAttribute(int minSize)
+ : base("{0} should be at least {1}.")
{
MinSize = minSize;
- ErrorMessage = ErrorMessage ?? "{0} should be at least {1}.";
}
///
@@ -33,7 +33,12 @@ public FileMinSizeAttribute(int minSize)
///
/// Get allowed of the file with appropriate unit.
///
- private string MinSizeAndUnit => MinSize >= 1024 ? Math.Round(MinSize / 1024M, 2) + " MB" : MinSize + " KB";
+ internal string MinSizeAndUnit => MinSize >= 1024 ? Math.Round(MinSize / 1024M, 2) + " MB" : MinSize + " KB";
+
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MinSizeAndUnit);
+ }
///
/// To check whether the input is smaller than the specified size.
@@ -72,8 +77,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
if (MinSize > 0 && fileLengthInKByte < MinSize)
{
- string formattedErrorMessage = string.Format(CultureInfo.InvariantCulture, ErrorMessage, validationContext.DisplayName, MinSizeAndUnit);
- return new ValidationResult(formattedErrorMessage);
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
else
diff --git a/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileTypeAttribute.cs b/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileTypeAttribute.cs
index 9fc1874..6666601 100644
--- a/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileTypeAttribute.cs
+++ b/src/TanvirArjel.CustomValidation.AspNetCore/Attributes/FileTypeAttribute.cs
@@ -17,24 +17,16 @@ namespace TanvirArjel.CustomValidation.AspNetCore.Attributes
///
public sealed class FileTypeAttribute : ValidationAttribute
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// A single value.
- public FileTypeAttribute(FileType fileType)
- {
- FileTypes = new FileType[] { fileType };
- ErrorMessage = ErrorMessage ?? "The {0} should be in {1} format.";
- }
-
///
/// This is used to validate file type of object.
///
/// An of .
- public FileTypeAttribute(FileType[] fileTypes)
+ public FileTypeAttribute(params FileType[] fileTypes)
+ : base("The {0} should be in {1} formats.")
{
FileTypes = fileTypes;
- ErrorMessage = ErrorMessage ?? "The {0} should be in {1} formats.";
+ string[] validFileTypeNames = FileTypes.Select(ft => ft.ToString("G")).ToArray();
+ ValidFileTypeNamesString = string.Join(",", validFileTypeNames);
}
///
@@ -42,6 +34,16 @@ public FileTypeAttribute(FileType[] fileTypes)
///
public FileType[] FileTypes { get; }
+ ///
+ /// Valid file types string
+ ///
+ internal string ValidFileTypeNamesString { get; }
+
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, ValidFileTypeNamesString);
+ }
+
///
/// To check whether the input is type of the specified type.
///
@@ -81,10 +83,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
validFileTypes = validFileTypes.SelectMany(vft => vft.Split(',')).ToArray();
if (!validFileTypes.Contains(inputFile.ContentType.ToUpperInvariant()))
{
- string[] validFileTypeNames = FileTypes.Select(ft => ft.ToString("G")).ToArray();
- string validFileTypeNamesString = string.Join(",", validFileTypeNames);
- string fileTypeErrorMessage = GetFileTypeErrorMessage(ErrorMessage, validationContext.DisplayName, validFileTypeNamesString);
- return new ValidationResult(fileTypeErrorMessage);
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
}
@@ -96,10 +95,5 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
return ValidationResult.Success;
}
-
- private static string GetFileTypeErrorMessage(string errorMessageString, string propertyName, string fileTypeNamesString)
- {
- return string.Format(CultureInfo.InvariantCulture, errorMessageString, propertyName, fileTypeNamesString);
- }
}
}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/CompareToAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/CompareToAttribute.cs
index eaed079..2d6b58d 100644
--- a/src/TanvirArjel.CustomValidation/Attributes/CompareToAttribute.cs
+++ b/src/TanvirArjel.CustomValidation/Attributes/CompareToAttribute.cs
@@ -51,7 +51,7 @@ public enum ComparisonType
/// This is used to compare the decorated property value against the another property value of the same object.
///
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
- public sealed class CompareToAttribute : ValidationAttribute
+ public class CompareToAttribute : ValidationAttribute
{
///
/// Initializes a new instance of the class.
@@ -59,14 +59,10 @@ public sealed class CompareToAttribute : ValidationAttribute
/// Name of the property which against the comparison will be done.
/// The .
public CompareToAttribute(string comparePropertyName, ComparisonType comparisonType)
+ : base(GetErrorMessage(comparisonType))
{
ComparePropertyName = comparePropertyName;
ComparisonType = comparisonType;
-
- if (ErrorMessage == null)
- {
- SetErrorMessage(comparisonType);
- }
}
///
@@ -152,7 +148,7 @@ ValidationResult TriggerValueComparison()
DisplayAttribute comparePropertyDisplayAttribute = comparePropertyInfo.GetCustomAttributes(typeof(DisplayAttribute), true).FirstOrDefault() as DisplayAttribute;
string comparePropertyDisplayName = comparePropertyDisplayAttribute?.GetName() ?? ComparePropertyName;
- string errorMessage = string.Format(CultureInfo.InvariantCulture, ErrorMessage, propertyDisplayName, comparePropertyDisplayName);
+ string errorMessage = string.Format(CultureInfo.CurrentCulture, ErrorMessageString, propertyDisplayName, comparePropertyDisplayName);
// Cast value to the appropriate dynamic type.
dynamic propertyValueDynamic;
@@ -180,7 +176,7 @@ ValidationResult TriggerValueComparison()
}
else
{
- throw new Exception($"The type is not supported in {nameof(RequiredIfAttribute)}.");
+ throw new Exception($"The type is not supported in {nameof(CompareToAttribute)}.");
}
// Do comaprison and do the required validation.
@@ -231,28 +227,22 @@ ValidationResult TriggerValueComparison()
}
}
- private void SetErrorMessage(ComparisonType comparisonType)
+ private static string GetErrorMessage(ComparisonType comparisonType)
{
switch (comparisonType)
{
case ComparisonType.Equal:
- ErrorMessage = "The {0} is not equal to {1}.";
- break;
+ return "The {0} is not equal to {1}.";
case ComparisonType.NotEqual:
- ErrorMessage = "The {0} can not be equal to {1}.";
- break;
+ return "The {0} can not be equal to {1}.";
case ComparisonType.GreaterThan:
- ErrorMessage = "The {0} should be greater than {1}.";
- break;
+ return "The {0} should be greater than {1}.";
case ComparisonType.GreaterThanOrEqual:
- ErrorMessage = "The {0} should be greater than or equal {1}.";
- break;
+ return "The {0} should be greater than or equal {1}.";
case ComparisonType.SmallerThan:
- ErrorMessage = "The {0} should be smaller than {1}.";
- break;
+ return "The {0} should be smaller than {1}.";
case ComparisonType.SmallerThanOrEqual:
- ErrorMessage = "The {0} should be smaller than or equal {1}.";
- break;
+ return "The {0} should be smaller than or equal {1}.";
default:
throw new ArgumentNullException(nameof(comparisonType));
}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/FixedLengthAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/FixedLengthAttribute.cs
index fc9f400..dbf102a 100644
--- a/src/TanvirArjel.CustomValidation/Attributes/FixedLengthAttribute.cs
+++ b/src/TanvirArjel.CustomValidation/Attributes/FixedLengthAttribute.cs
@@ -21,9 +21,9 @@ public sealed class FixedLengthAttribute : ValidationAttribute
///
/// A positive value.
public FixedLengthAttribute(int fixedLength)
+ : base("The {0} should be exactly {1} characters long.")
{
FixedLength = fixedLength;
- ErrorMessage = ErrorMessage ?? "The {0} should be exactly {1} characters long.";
}
///
@@ -31,6 +31,11 @@ public FixedLengthAttribute(int fixedLength)
///
public int FixedLength { get; }
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, FixedLength);
+ }
+
///
/// To check whether the input value has exactly same as specified.
///
@@ -64,17 +69,11 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
if (inputValue.Length != FixedLength)
{
- string errorMessage = GetFormattedErrorMessage(ErrorMessage, validationContext.DisplayName, FixedLength);
- return new ValidationResult(errorMessage);
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
return ValidationResult.Success;
}
-
- private static string GetFormattedErrorMessage(string errorMessage, string propertyName, int fixedLength)
- {
- return string.Format(CultureInfo.InvariantCulture, errorMessage, propertyName, fixedLength);
- }
}
}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/MaxAgeAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/MaxAgeAttribute.cs
index dba3051..8a968fc 100644
--- a/src/TanvirArjel.CustomValidation/Attributes/MaxAgeAttribute.cs
+++ b/src/TanvirArjel.CustomValidation/Attributes/MaxAgeAttribute.cs
@@ -4,6 +4,7 @@
using System;
using System.ComponentModel.DataAnnotations;
+using System.Globalization;
using System.Reflection;
namespace TanvirArjel.CustomValidation.Attributes
@@ -22,33 +23,25 @@ public sealed class MaxAgeAttribute : ValidationAttribute
/// A value in between 0 and 11.
/// A value in between 0 and 31.
public MaxAgeAttribute(int years, int months, int days)
+ : base("The {0} cannot be smaller than {1}.")
{
- Years = years < 0 ? 0 : years;
- Months = years < 0 ? 0 : months;
- Days = days < 0 ? 0 : days;
-
- ErrorMessage = ErrorMessage ?? $"The Maximum age can be {(Years > 0 ? years + " years" : string.Empty)} {(Months > 0 ? months + " months" : string.Empty)} {(Days > 0 ? days + " days." : string.Empty)}";
+ MaxAgeDateTime = DateTime.Today.AddYears(years < 0 ? 0 : -years).AddMonths(months < 0 ? 0 : -months).AddDays(days < 0 ? 0 : -days);
}
///
- /// Get the year value of the max allowed age.
- ///
- public int Years { get; }
-
- ///
- /// Get the month value of the max allowed age.
+ /// Get the allowed min date value.
///
- public int Months { get; }
+ public DateTime MaxAgeDateTime { get; }
///
- /// Get the day value of the max allowed age.
+ /// Gets the format of the that will be used in
///
- public int Days { get; }
+ public string ErrorMessageMaxAgeDateTimeFormat { get; set; } = "dd-MM-yyyy";
- ////public override string FormatErrorMessage(string displayName)
- ////{
- //// return string.Format(CultureInfo.InvariantCulture, this.ErrorMessage, this.Years, this.Months, this.Days);
- ////}
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MaxAgeDateTime.ToString(ErrorMessageMaxAgeDateTimeFormat, CultureInfo.CurrentCulture));
+ }
///
/// To check whether the input date violates the specified max age constraint.
@@ -86,18 +79,13 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
return new ValidationResult($"{validationContext.DisplayName} can not be greater than today's date.");
}
- DateTime dateNow = DateTime.Now;
- TimeSpan timeSpan = dateNow.Subtract(dateOfBirth);
- DateTime ageDateTime = DateTime.MinValue.Add(timeSpan);
-
- DateTime maxAgeDateTime = DateTime.MinValue.AddYears(Years).AddMonths(Months).AddDays(Days);
+ //DateTime dateNow = DateTime.Now;
+ //TimeSpan timeSpan = dateNow.Subtract(dateOfBirth);
+ //DateTime ageDateTime = DateTime.MinValue.Add(timeSpan);
- if (Years > 0 || Months > 0 || Days > 0)
+ if (dateOfBirth > MaxAgeDateTime)
{
- if (ageDateTime > maxAgeDateTime)
- {
- return new ValidationResult(ErrorMessage);
- }
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/MaxDateAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/MaxDateAttribute.cs
index e089ac2..4667fe6 100644
--- a/src/TanvirArjel.CustomValidation/Attributes/MaxDateAttribute.cs
+++ b/src/TanvirArjel.CustomValidation/Attributes/MaxDateAttribute.cs
@@ -23,9 +23,9 @@ public sealed class MaxDateAttribute : ValidationAttribute
/// A calendar month number. The value should be in 1 to 12.
/// A calendar date. The value should be in 1 to 31.
public MaxDateAttribute(int year, int month, int day)
+ : base("The {0} cannot be larger than {1}.")
{
MaxDate = new DateTime(year, month, day);
- ErrorMessage = ErrorMessage ?? "The {0} cannot be larger than {1}.";
}
///
@@ -34,6 +34,7 @@ public MaxDateAttribute(int year, int month, int day)
/// The representation of the minDate value.
/// Format of the supplied string minDate value.
public MaxDateAttribute(string maxDate, string format)
+ : base("The {0} cannot be larger than {1}.")
{
MaxDate = DateTime.ParseExact(maxDate, format, CultureInfo.InvariantCulture);
}
@@ -43,10 +44,15 @@ public MaxDateAttribute(string maxDate, string format)
///
public DateTime MaxDate { get; }
- ////public override string FormatErrorMessage(string displayName)
- ////{
- //// return string.Format(CultureInfo.InvariantCulture, ErrorMessage, displayName, MaxDate.ToString("dd-MMM-yyyy", CultureInfo.InvariantCulture));
- ////}
+ ///
+ /// Gets the format of the that will be used in
+ ///
+ public string ErrorMessageMaxDateFormat { get; set; } = "dd-MM-yyyy";
+
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MaxDate.ToString(ErrorMessageMaxDateFormat, CultureInfo.CurrentCulture));
+ }
///
/// To check whether the input date violates the specified max date constraint.
@@ -83,8 +89,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
if (inputDate > MaxDate)
{
- string errorMessage = FormatErrorMessage(validationContext.DisplayName);
- return new ValidationResult(errorMessage);
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/MinAgeAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/MinAgeAttribute.cs
index ff1618a..e0d6673 100644
--- a/src/TanvirArjel.CustomValidation/Attributes/MinAgeAttribute.cs
+++ b/src/TanvirArjel.CustomValidation/Attributes/MinAgeAttribute.cs
@@ -4,6 +4,7 @@
using System;
using System.ComponentModel.DataAnnotations;
+using System.Globalization;
namespace TanvirArjel.CustomValidation.Attributes
{
@@ -21,33 +22,25 @@ public sealed class MinAgeAttribute : ValidationAttribute
/// A positive value ranging from 0 to 11.
/// A positive value ranging from 0 to 31.
public MinAgeAttribute(int years, int months, int days)
+ : base("The {0} cannot be larger than {1}.")
{
- Years = years < 0 ? 0 : years;
- Months = months < 0 ? 0 : months;
- Days = days < 0 ? 0 : days;
-
- ErrorMessage = ErrorMessage ?? $"The Minimum age should be {(Years > 0 ? years + " years" : string.Empty)} {(Months > 0 ? months + " months" : string.Empty)} {(Days > 0 ? days + " days." : string.Empty)}";
+ MinAgeDateTime = DateTime.Today.AddYears(years < 0 ? 0 : -years).AddMonths(months < 0 ? 0 : -months).AddDays(days < 0 ? 0 : -days);
}
///
- /// Get the year value of the allowed min age.
- ///
- public int Years { get; }
-
- ///
- /// Get the month value of the allowed min age.
+ /// Get the allowed max date value.
///
- public int Months { get; }
+ public DateTime MinAgeDateTime { get; }
///
- /// Get the day value of the allowed min age.
+ /// Gets the format of the that will be used in
///
- public int Days { get; }
+ public string ErrorMessageMinAgeDateTimeFormat { get; set; } = "dd-MM-yyyy";
- ////public override string FormatErrorMessage(string displayName)
- ////{
- //// return string.Format(CultureInfo.InvariantCulture, ErrorMessage, Years, Months, Days);
- ////}
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MinAgeDateTime.ToString(ErrorMessageMinAgeDateTimeFormat, CultureInfo.CurrentCulture));
+ }
///
/// To check whether the input date violates the specified min age constraint.
@@ -83,18 +76,13 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
return new ValidationResult($"{validationContext.DisplayName} can not be greater than today's date.");
}
- DateTime dateNow = DateTime.Now;
- TimeSpan timeSpan = dateNow.Subtract(dateOfBirth);
- DateTime ageDateTime = DateTime.MinValue.Add(timeSpan);
-
- DateTime minAgeDateTime = DateTime.MinValue.AddYears(Years).AddMonths(Months).AddDays(Days);
+ //DateTime dateNow = DateTime.Now;
+ //TimeSpan timeSpan = dateNow.Subtract(dateOfBirth);
+ //DateTime ageDateTime = DateTime.MinValue.Add(timeSpan);
- if (Years > 0 || Months > 0 || Days > 0)
+ if (MinAgeDateTime > dateOfBirth)
{
- if (minAgeDateTime > ageDateTime)
- {
- return new ValidationResult(ErrorMessage);
- }
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/MinDateAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/MinDateAttribute.cs
index b657eaa..c5a7a3d 100644
--- a/src/TanvirArjel.CustomValidation/Attributes/MinDateAttribute.cs
+++ b/src/TanvirArjel.CustomValidation/Attributes/MinDateAttribute.cs
@@ -23,9 +23,9 @@ public sealed class MinDateAttribute : ValidationAttribute
/// A calendar month number. The value should be in 1 to 12.
/// A calendar date. The value should be in 1 to 31.
public MinDateAttribute(int year, int month, int day)
+ : base("The {0} cannot be smaller than {1}.")
{
MinDate = new DateTime(year, month, day);
- ErrorMessage = ErrorMessage ?? "The {0} cannot be smaller than {1}.";
}
///
@@ -34,6 +34,7 @@ public MinDateAttribute(int year, int month, int day)
/// The representation of the minDate value.
/// Format of the supplied string minDate value.
public MinDateAttribute(string minDate, string format)
+ : base("The {0} cannot be smaller than {1}.")
{
MinDate = DateTime.ParseExact(minDate, format, CultureInfo.InvariantCulture);
}
@@ -43,10 +44,15 @@ public MinDateAttribute(string minDate, string format)
///
public DateTime MinDate { get; }
- ////public override string FormatErrorMessage(string displayName)
- ////{
- //// return string.Format(CultureInfo.InvariantCulture, ErrorMessage, displayName, MinDate.ToString("dd-MMM-yyyy", CultureInfo.InvariantCulture));
- ////}
+ ///
+ /// Gets the format of the that will be used in
+ ///
+ public string ErrorMessageMinDateFormat { get; set; } = "dd-MM-yyyy";
+
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MinDate.ToString(ErrorMessageMinDateFormat, CultureInfo.CurrentCulture));
+ }
///
/// To check whether the input date violates the specified min date constraint.
@@ -83,8 +89,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
if (inputDate < MinDate)
{
- string errorMessage = FormatErrorMessage(validationContext.DisplayName);
- return new ValidationResult(errorMessage);
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/RequiredIfAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/RequiredIfAttribute.cs
index 399a9fa..a4aef44 100644
--- a/src/TanvirArjel.CustomValidation/Attributes/RequiredIfAttribute.cs
+++ b/src/TanvirArjel.CustomValidation/Attributes/RequiredIfAttribute.cs
@@ -23,11 +23,11 @@ public sealed class RequiredIfAttribute : ValidationAttribute
/// The type of the other property supplied value.
/// The value against comparison will be done.
public RequiredIfAttribute(string otherPropertyName, ComparisonType comparisonType, object otherPropertyValue)
+ : base("The {0} field is required.")
{
OtherPropertyName = otherPropertyName;
ComparisonType = comparisonType;
OtherPropertyValue = otherPropertyValue;
- ErrorMessage = ErrorMessage ?? "The {0} field is required.";
}
///
@@ -191,7 +191,7 @@ private ValidationResult IsRequired(object value, ValidationContext validationCo
{
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
{
- string formattedErrorMessage = string.Format(CultureInfo.InvariantCulture, ErrorMessage, validationContext.DisplayName);
+ string formattedErrorMessage = string.Format(CultureInfo.CurrentCulture, ErrorMessageString, validationContext.DisplayName);
return new ValidationResult(formattedErrorMessage);
}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/TextEditorAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/TextEditorAttribute.cs
new file mode 100644
index 0000000..1ca1fd2
--- /dev/null
+++ b/src/TanvirArjel.CustomValidation/Attributes/TextEditorAttribute.cs
@@ -0,0 +1,106 @@
+//
+// Copyright (c) TanvirArjel. All rights reserved.
+//
+
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Globalization;
+using System.Reflection;
+using System.Text.RegularExpressions;
+
+namespace TanvirArjel.CustomValidation.Attributes
+{
+ ///
+ /// This is used to make online text editor field, like TinyMCE, required along with an option for setting minimum length.
+ ///
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
+ public sealed class TextEditorAttribute : ValidationAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TextEditorAttribute()
+ {
+ ErrorMessage = ErrorMessage ?? "{0} field is required.";
+ MinLengthErrorMessage = MinLengthErrorMessage ?? "{0} should be at least {1} characters long.";
+ MaxLengthErrorMessage = MaxLengthErrorMessage ?? "{0} cannot be more than {1} characters long.";
+ }
+
+ ///
+ /// Get and set the minimum length of the text editor field. The value should be a positive number.
+ ///
+ public int MinLength { get; set; }
+
+ ///
+ /// Get and set the maximum length of the text editor field. The value should be a positive number.
+ ///
+ public int MaxLength { get; set; }
+
+ ///
+ /// Get and set the error message if the MinLength validation fails.
+ ///
+ public string MinLengthErrorMessage { get; set; }
+
+ ///
+ /// Get and set the error message if the MaxLength validaton fails.
+ ///
+ public string MaxLengthErrorMessage { get; set; }
+
+ ///
+ /// To check whether the input date violates the required constraint.
+ ///
+ /// Type of .
+ /// The request validation context.
+ /// Returns .
+ /// Thrown if is null.
+ protected override ValidationResult IsValid(object value, ValidationContext validationContext)
+ {
+ if (validationContext == null)
+ {
+ throw new ArgumentNullException(nameof(validationContext));
+ }
+
+ PropertyInfo propertyInfo = validationContext.ObjectType.GetProperty(validationContext.MemberName);
+
+ if (propertyInfo == null)
+ {
+ throw new ArgumentException($"The object does not contain any property with name '{validationContext.MemberName}'");
+ }
+
+ if (propertyInfo.PropertyType != typeof(string))
+ {
+ throw new ArgumentException($"The {nameof(TextEditorAttribute)} is not valid on property type {propertyInfo.PropertyType}" +
+ $"This Attribute is only valid on {typeof(string)}");
+ }
+
+ string requiredErrorMessage = string.Format(CultureInfo.InvariantCulture, ErrorMessage, validationContext.DisplayName);
+
+ if (value == null)
+ {
+ return new ValidationResult(requiredErrorMessage);
+ }
+
+ string inputValue = value.ToString();
+ string inputValueWithoutHtml = Regex.Replace(inputValue, "<.*?>| ", string.Empty);
+
+ if (string.IsNullOrWhiteSpace(inputValueWithoutHtml))
+ {
+ return new ValidationResult(requiredErrorMessage);
+ }
+
+ if (MinLength > 0 && inputValueWithoutHtml.Length < MinLength)
+ {
+ string minLengthErrorMessage = string.Format(CultureInfo.InvariantCulture, MinLengthErrorMessage, validationContext.DisplayName, MinLength);
+ return new ValidationResult(minLengthErrorMessage);
+ }
+
+ if (MaxLength > 0 && inputValueWithoutHtml.Length > MaxLength)
+ {
+ string maxLengthErrorMessage = string.Format(CultureInfo.InvariantCulture, MaxLengthErrorMessage, validationContext.DisplayName, MaxLength);
+ return new ValidationResult(maxLengthErrorMessage);
+ }
+
+ return ValidationResult.Success;
+ }
+ }
+}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/TextEditorMaxLengthAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/TextEditorMaxLengthAttribute.cs
new file mode 100644
index 0000000..05e0b51
--- /dev/null
+++ b/src/TanvirArjel.CustomValidation/Attributes/TextEditorMaxLengthAttribute.cs
@@ -0,0 +1,80 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Globalization;
+using System.Reflection;
+using System.Text.RegularExpressions;
+
+namespace TanvirArjel.CustomValidation.Attributes
+{
+ ///
+ /// This is used to validate the WYSIWYG editor text max length
+ ///
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
+ public sealed class TextEditorMaxLengthAttribute : ValidationAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TextEditorMaxLengthAttribute()
+ : base("{0} cannot be more than {1} characters long.")
+ { }
+
+ ///
+ /// Get and set the maximum length of the text editor field. The value should be a positive number.
+ ///
+ public int MaxLength { get; }
+
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MaxLength);
+ }
+
+ ///
+ /// To check whether the input text violates the required constraint.
+ ///
+ /// Type of .
+ /// The request validation context.
+ /// Returns .
+ /// Thrown if is null.
+ protected override ValidationResult IsValid(object value, ValidationContext validationContext)
+ {
+ if (validationContext == null)
+ {
+ throw new ArgumentNullException(nameof(validationContext));
+ }
+
+ PropertyInfo propertyInfo = validationContext.ObjectType.GetProperty(validationContext.MemberName);
+
+ if (propertyInfo == null)
+ {
+ throw new ArgumentException($"The object does not contain any property with name '{validationContext.MemberName}'");
+ }
+
+ if (propertyInfo.PropertyType != typeof(string))
+ {
+ throw new ArgumentException($"The {nameof(TextEditorMaxLengthAttribute)} is not valid on property type {propertyInfo.PropertyType}" +
+ $"This Attribute is only valid on {typeof(string)}");
+ }
+
+ if (value == null)
+ {
+ return ValidationResult.Success;
+ }
+
+ string inputValue = value.ToString();
+ string inputValueWithoutHtml = Regex.Replace(inputValue, "<.*?>| ", string.Empty);
+
+ if (string.IsNullOrWhiteSpace(inputValueWithoutHtml))
+ {
+ return ValidationResult.Success;
+ }
+
+ if (MaxLength > 0 && inputValueWithoutHtml.Length > MaxLength)
+ {
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
+ }
+
+ return ValidationResult.Success;
+ }
+ }
+}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/TextEditorMinLengthAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/TextEditorMinLengthAttribute.cs
new file mode 100644
index 0000000..1d7d3bf
--- /dev/null
+++ b/src/TanvirArjel.CustomValidation/Attributes/TextEditorMinLengthAttribute.cs
@@ -0,0 +1,82 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Globalization;
+using System.Reflection;
+using System.Text.RegularExpressions;
+
+namespace TanvirArjel.CustomValidation.Attributes
+{
+ ///
+ /// This is used to validate the WYSIWYG editor text min length
+ ///
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
+ public sealed class TextEditorMinLengthAttribute : ValidationAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TextEditorMinLengthAttribute()
+ : base("{0} should be at least {1} characters long.")
+ { }
+
+ ///
+ /// Get and set the minimum length of the text editor field. The value should be a positive number.
+ ///
+ public int MinLength { get; }
+
+ public override string FormatErrorMessage(string name)
+ {
+ return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MinLength);
+ }
+
+ ///
+ /// To check whether the input text violates the required constraint.
+ ///
+ /// Type of .
+ /// The request validation context.
+ /// Returns .
+ /// Thrown if is null.
+ protected override ValidationResult IsValid(object value, ValidationContext validationContext)
+ {
+ if (validationContext == null)
+ {
+ throw new ArgumentNullException(nameof(validationContext));
+ }
+
+ PropertyInfo propertyInfo = validationContext.ObjectType.GetProperty(validationContext.MemberName);
+
+ if (propertyInfo == null)
+ {
+ throw new ArgumentException($"The object does not contain any property with name '{validationContext.MemberName}'");
+ }
+
+ if (propertyInfo.PropertyType != typeof(string))
+ {
+ throw new ArgumentException($"The {nameof(TextEditorMinLengthAttribute)} is not valid on property type {propertyInfo.PropertyType}" +
+ $"This Attribute is only valid on {typeof(string)}");
+ }
+
+ string requiredErrorMessage = string.Format(CultureInfo.CurrentCulture, ErrorMessageString, validationContext.DisplayName);
+
+ if (value == null)
+ {
+ return MinLength > 0 ? new ValidationResult(FormatErrorMessage(validationContext.DisplayName)) : ValidationResult.Success;
+ }
+
+ string inputValue = value.ToString();
+ string inputValueWithoutHtml = Regex.Replace(inputValue, "<.*?>| ", string.Empty);
+
+ if (string.IsNullOrWhiteSpace(inputValueWithoutHtml))
+ {
+ return new ValidationResult(requiredErrorMessage);
+ }
+
+ if (MinLength > 0 && inputValueWithoutHtml.Length < MinLength)
+ {
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
+ }
+
+ return ValidationResult.Success;
+ }
+ }
+}
diff --git a/src/TanvirArjel.CustomValidation/Attributes/TextEditorRequiredAttribute.cs b/src/TanvirArjel.CustomValidation/Attributes/TextEditorRequiredAttribute.cs
index 1d6f5cb..e5118ec 100644
--- a/src/TanvirArjel.CustomValidation/Attributes/TextEditorRequiredAttribute.cs
+++ b/src/TanvirArjel.CustomValidation/Attributes/TextEditorRequiredAttribute.cs
@@ -1,50 +1,23 @@
-//
-// Copyright (c) TanvirArjel. All rights reserved.
-//
-
-using System;
+using System;
using System.ComponentModel.DataAnnotations;
-using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions;
namespace TanvirArjel.CustomValidation.Attributes
{
///
- /// This is used to make online text editor field, like TinyMCE, required along with an option for setting minimum length.
+ /// This is used to make WYSIWYG editor text value required
///
- [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
+ [AttributeUsage(
+ AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter,
+ AllowMultiple = false)]
public sealed class TextEditorRequiredAttribute : ValidationAttribute
{
///
/// Initializes a new instance of the class.
///
public TextEditorRequiredAttribute()
- {
- ErrorMessage = ErrorMessage ?? "{0} field is required.";
- MinLengthErrorMessage = MinLengthErrorMessage ?? "{0} should be at least {1} characters long.";
- MaxLengthErrorMessage = MaxLengthErrorMessage ?? "{0} cannot be more than {1} characters long.";
- }
-
- ///
- /// Get and set the minimum length of the text editor field. The value should be a positive number.
- ///
- public int MinLength { get; set; }
-
- ///
- /// Get and set the maximum length of the text editor field. The value should be a positive number.
- ///
- public int MaxLength { get; set; }
-
- ///
- /// Get and set the error message if the MinLength validation fails.
- ///
- public string MinLengthErrorMessage { get; set; }
-
- ///
- /// Get and set the error message if the MaxLength validaton fails.
- ///
- public string MaxLengthErrorMessage { get; set; }
+ : base("{0} field is required.") { }
///
/// To check whether the input date violates the required constraint.
@@ -64,20 +37,20 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
if (propertyInfo == null)
{
- throw new ArgumentException($"The object does not contain any property with name '{validationContext.MemberName}'");
+ throw new ArgumentException(
+ $"The object does not contain any property with name '{validationContext.MemberName}'");
}
if (propertyInfo.PropertyType != typeof(string))
{
- throw new ArgumentException($"The {nameof(TextEditorRequiredAttribute)} is not valid on property type {propertyInfo.PropertyType}" +
- $"This Attribute is only valid on {typeof(string)}");
+ throw new ArgumentException(
+ $"The {nameof(TextEditorRequiredAttribute)} is not valid on property type {propertyInfo.PropertyType}" +
+ $"This Attribute is only valid on {typeof(string)}");
}
- string requiredErrorMessage = string.Format(CultureInfo.InvariantCulture, ErrorMessage, validationContext.DisplayName);
-
if (value == null)
{
- return new ValidationResult(requiredErrorMessage);
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
string inputValue = value.ToString();
@@ -85,19 +58,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali
if (string.IsNullOrWhiteSpace(inputValueWithoutHtml))
{
- return new ValidationResult(requiredErrorMessage);
- }
-
- if (MinLength > 0 && inputValueWithoutHtml.Length < MinLength)
- {
- string minLengthErrorMessage = string.Format(CultureInfo.InvariantCulture, MinLengthErrorMessage, validationContext.DisplayName, MinLength);
- return new ValidationResult(minLengthErrorMessage);
- }
-
- if (MaxLength > 0 && inputValueWithoutHtml.Length > MaxLength)
- {
- string maxLengthErrorMessage = string.Format(CultureInfo.InvariantCulture, MaxLengthErrorMessage, validationContext.DisplayName, MaxLength);
- return new ValidationResult(maxLengthErrorMessage);
+ return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
return ValidationResult.Success;