Skip to content

Instantly share code, notes, and snippets.

@ognyandim
Last active August 22, 2017 09:07
Show Gist options
  • Save ognyandim/91a6c2db6b914fa97809948e5b6e269e to your computer and use it in GitHub Desktop.
Save ognyandim/91a6c2db6b914fa97809948e5b6e269e to your computer and use it in GitHub Desktop.
Validator for cross cutting concerns
using Castle.Components.DictionaryAdapter;
using Castle.Core;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel;
using Castle.MicroKernel.Context;
using Castle.MicroKernel.Handlers;
using Castle.MicroKernel.Lifestyle;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using System;
using System.Collections;
using System.Configuration;
using Core.Common;
using Core.Common.Interfaces;
//...
namespace Core.Installer
{
public class CoreComponetInstaller : IWindsorInstaller
{
//...
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
//...
Component.For<IValidationService>().ImplementedBy<DefaultValidationService>(),
//...
);
container.Install(CastleConfig.FromAppConfig());
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text.RegularExpressions;
using Core.Common.Interfaces;
namespace Core.Common
{
/// <summary>
/// Validation class
/// </summary>
public class DefaultValidationService : IValidationService
{
//private static readonly Regex MailRegex = new Regex("^[_a-z0-9-]+(.[_a-z0-9-]+)*@[a-z0-9-]+(.[a-z0-9-]+)*(.[a-z]{2,4})$"); // Not working
private static readonly Regex MailRegex = new Regex(@"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
//private static readonly Regex GuidRegex = new Regex(@"\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b");
private static readonly Regex GuidRegex = new Regex(@"^[{(]?[0-9A-F]{8}[-]?([0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$", RegexOptions.IgnoreCase);
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void Null(object paramValue, string paramName)
{
if (paramValue == null)
{
throw new ArgumentException("Parameter must not be null.", paramName ?? "");
}
}
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void StringIsNullOrEmpty(string paramValue, string paramName)
{
if (string.IsNullOrEmpty(paramValue))
{
throw new ArgumentException(
"String parameter is null or empty",
paramName ?? "");
}
}
[DebuggerStepThrough]
public void CollectionIsNotNullOrEmpty(IEnumerable<object> paramValue, string paramName)
{
this.Null(paramValue, paramName);
if (!paramValue.Any())
{
throw new ArgumentException("Collection can not be empty.", paramName ?? "");
}
}
public void CollectionIsNotNullOrEmpty(IEnumerable<int> paramValue, string paramName)
{
this.Null(paramValue, paramName);
if (!paramValue.Any())
{
throw new ArgumentException("Collection can not be empty.", paramName ?? "");
}
}
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void EntityId(int paramValue, string paramName)
{
if (paramValue <= 0)
{
throw new ArgumentException("Entity id must be greater then 0.", paramName ?? "");
}
}
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="FileNotFoundException"></exception>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void FileExists(string paramValue, string paramName)
{
StringIsNullOrEmpty(paramValue, paramName);
if (!File.Exists(paramValue))
{
throw new FileNotFoundException("File does not exist", paramName ?? "");
}
}
[DebuggerStepThrough]
public void Email(string email, string paramName)
{
StringIsNullOrEmpty(email, paramName);
if (!MailRegex.IsMatch(email.ToLower()))
{
throw new ArgumentException($"Email '{email}' is not a valid email in parameter {paramName}.");
}
}
[DebuggerStepThrough]
public bool IsEmail(string email, string paramName)
{
return MailRegex.IsMatch(email.ToLower());
}
[DebuggerStepThrough]
public void GuidString(string guidString, string paramName)
{
StringIsNullOrEmpty(guidString, paramName);
if (!GuidRegex.IsMatch(guidString))
{
throw new ArgumentException($"String '{guidString}' is not a valid guid string in parameter '{paramName}'.");
}
}
[DebuggerStepThrough]
public void IsPositive(decimal decimalNumber, string paramName)
{
if (decimalNumber < 0)
{
throw new ArgumentException($"Decimal '{decimalNumber.ToString(CultureInfo.InvariantCulture)}' is negative in parameter {paramName}.");
}
}
[DebuggerStepThrough]
public void IsValidSqlDate(DateTime dateTime)
{
DateTime minDateTime = new DateTime(1753, 1, 1);
DateTime maxDateTime = new DateTime(9999, 12, 31, 23, 59, 59, 997);
if (dateTime >= minDateTime && dateTime <= maxDateTime)
{
return;
}
throw new ArgumentOutOfRangeException("Date is not in SQL Date range :January 1, 1753 to December 31, 9999");
}
[DebuggerStepThrough]
public bool IsUri(string uriParamValue, string uriParamName)
{
if (!string.IsNullOrEmpty(uriParamValue) && Uri.IsWellFormedUriString(uriParamValue, UriKind.RelativeOrAbsolute))
{
Uri tempValue;
return (Uri.TryCreate(uriParamValue, UriKind.RelativeOrAbsolute, out tempValue));
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void DirectoryExists(string paramValue, string paramName)
{
StringIsNullOrEmpty(paramValue, paramName);
if (!Directory.Exists(paramValue))
{
throw new ArgumentException("Directory does not exist", paramName ?? "");
}
}
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void CheckAzureTableName(string paramValue, string paramName)
{
Null(paramValue, paramName);
Regex regex = new Regex("^[A-Za-z][A-Za-z0-9]{2,62}$", RegexOptions.Compiled);
if (!regex.IsMatch(paramValue))
{
throw new ArgumentException(
"Table names must conform to these rules: " + "May contain only alphanumeric characters. "
+ "Cannot begin with a numeric character. " + "Are case-insensitive. "
+ "Must be from 3 to 63 characters long.",
paramName ?? "");
}
}
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void CheckAzureTablePropertyValue(string paramValue, string paramName)
{
Null(paramValue, paramName);
Regex regex = new Regex(@"^[^/\\#?]{0,1024}$", RegexOptions.Compiled);
if (!regex.IsMatch(paramValue))
{
throw new ArgumentException(
"Table property values must conform to these rules: "
+ "Must not contain the forward slash (/), backslash (\\), number sign (#), or question mark (?) characters. "
+ "Must be from 1 to 1024 characters long.",
paramName ?? "");
}
}
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void CheckAzureBlobContainerName(string paramValue, string paramName)
{
Null(paramValue, paramName);
Regex regex = new Regex("^(?-i)(?:[a-z0-9]|(?<=[0-9a-z])-(?=[0-9a-z])){3,63}$", RegexOptions.Compiled);
if (!regex.IsMatch(paramValue))
{
throw new ArgumentException(
"Blob container names must conform to these rules: "
+ "Must start with a letter or number, and can contain only letters, numbers, and the dash (-) character. "
+ "Every dash (-) character must be immediately preceded and followed by a letter or number; consecutive dashes are not permitted in container names. "
+ "All letters in a container name must be lowercase. " + "Must be from 3 to 63 characters long.",
paramName ?? "");
}
}
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void CheckAzureBlobName(string paramValue, string paramName)
{
StringIsNullOrEmpty(paramValue, paramName);
if (paramValue.Length > 1024)
{
throw new ArgumentException(
"Blob names must conform to these rules: " + "Must be from 1 to 1024 characters long.",
paramName ?? "");
}
}
[DebuggerStepThrough]
public void QueueName(string paramValue, string paramName)
{
Null(paramValue, paramName);
Regex regex = new Regex("^(?-i)(?:[a-z0-9]|(?<=[0-9a-z])-(?=[0-9a-z])){3,63}$", RegexOptions.Compiled);
if (!regex.IsMatch(paramValue))
{
throw new ArgumentException(
"Queue names must conform to these rules: "
+ "Must start with a letter or number, and can contain only letters, numbers, and the dash (-) character. "
+ "The first and last letters in the queue name must be alphanumeric. The dash (-) character cannot be the first or last character. Consecutive dash characters are not permitted in the queue name. "
+ "All letters in a queue name must be lowercase. " + "Must be from 3 to 63 characters long.",
paramName ?? "");
}
}
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
[DebuggerStepThrough]
public void CheckAzureDatabaseName(string paramValue, string paramName)
{
Null(paramValue, paramName);
Regex regex = new Regex("^(?-i)(?:[a-z0-9]|(?<=[0-9a-z])-(?=[0-9a-z])){3,63}$", RegexOptions.Compiled);
if (!regex.IsMatch(paramValue))
{
throw new ArgumentException($"Wrong database name : {paramValue}. " +
$"Database names must conform to these rules: " +
$"1 Must start with a letter or number, and can contain only letters, numbers, and the dash (-) character. " +
$"2 Every dash (-) character must be immediately preceded and followed by a letter or number; consecutive dashes are not permitted in container names. " +
$"3 All letters in a container name must be lowercase. " +
$"4 Must be from 3 to 63 characters long.");
}
}
public IbanValidationResult Iban(string paramValue)
{
paramValue = Regex.Replace(paramValue, @"\s+", "");
// Check if value is missing
if (string.IsNullOrEmpty(paramValue))
return IbanValidationResult.ValueMissing;
if (paramValue.Length < 2)
return IbanValidationResult.ValueTooSmall;
var countryCode = paramValue.Substring(0, 2).ToUpper();
int lengthForCountryCode;
var countryCodeKnown = _lengths.TryGetValue(countryCode, out lengthForCountryCode);
if (!countryCodeKnown)
{
return IbanValidationResult.CountryCodeNotKnown;
}
// Check length.
if (paramValue.Length < lengthForCountryCode)
return IbanValidationResult.ValueTooSmall;
if (paramValue.Length > lengthForCountryCode)
return IbanValidationResult.ValueTooBig;
paramValue = paramValue.ToUpper();
var newIban = paramValue.Substring(4) + paramValue.Substring(0, 4);
newIban = Regex.Replace(newIban, @"\D", match => (match.Value[0] - 55).ToString());
var remainder = BigInteger.Parse(newIban) % 97;
if (remainder != 1)
return IbanValidationResult.ValueFailsModule97Check;
return IbanValidationResult.IsValid;
}
private static Dictionary<string, int> _lengths = new Dictionary<string, int>
{
{"AL", 28},
{"AD", 24},
{"AT", 20},
{"AZ", 28},
{"BE", 16},
{"BH", 22},
{"BA", 20},
{"BR", 29},
{"BG", 22},
{"CR", 21},
{"HR", 21},
{"CY", 28},
{"CZ", 24},
{"DK", 18},
{"DO", 28},
{"EE", 20},
{"FO", 18},
{"FI", 18},
{"FR", 27},
{"GE", 22},
{"DE", 22},
{"GI", 23},
{"GR", 27},
{"GL", 18},
{"GT", 28},
{"HU", 28},
{"IS", 26},
{"IE", 22},
{"IL", 23},
{"IT", 27},
{"KZ", 20},
{"KW", 30},
{"LV", 21},
{"LB", 28},
{"LI", 21},
{"LT", 20},
{"LU", 20},
{"MK", 19},
{"MT", 31},
{"MR", 27},
{"MU", 30},
{"MC", 27},
{"MD", 24},
{"ME", 22},
{"NL", 18},
{"NO", 15},
{"PK", 24},
{"PS", 29},
{"PL", 28},
{"PT", 25},
{"RO", 24},
{"SM", 27},
{"SA", 24},
{"RS", 22},
{"SK", 24},
{"SI", 19},
{"ES", 24},
{"SE", 24},
{"CH", 21},
{"TN", 24},
{"TR", 26},
{"AE", 23},
{"GB", 22},
{"VG", 24}
};
}
}
using System;
using System.Collections.Generic;
namespace Core.Common.Interfaces
{
public interface IValidationService
{
/// <summary>
/// Check if parameter is null
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void Null(object paramValue, string paramName);
/// <summary>
/// Check if the value of a string parameter is null or empty
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void StringIsNullOrEmpty(string paramValue, string paramName);
void CollectionIsNotNullOrEmpty(IEnumerable<object> paramValue, string paramName);
void CollectionIsNotNullOrEmpty(IEnumerable<int> paramValue, string paramName);
/// <summary>
/// Check if an integer is a valid database entity id
/// </summary>
/// <param name="entityId"></param>
/// <param name="entityName"></param>
/// <exception cref="ArgumentException"></exception>
void EntityId(int entityId, string entityName);
/// <summary>
/// Check if a file exists on disk
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void FileExists(string paramValue, string paramName);
/// <summary>
/// Check if an email is a valid email
/// </summary>
/// <param name="email"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void Email(string email, string paramName);
/// <summary>
/// Check if an email is a valid email
/// </summary>
/// <param name="email"></param>
/// <param name="paramName"></param>
/// <returns>Bool</returns>
bool IsEmail(string email, string paramName);
/// <summary>
/// Check if a guid string is a valid guid
/// </summary>
/// <param name="guidString"></param>
/// <param name="paramName"></param>
void GuidString(string guidString, string paramName);
/// <summary>
/// Check if a number is positive
/// </summary>
/// <param name="decimalNumber"></param>
/// <param name="paramName"></param>
void IsPositive(decimal decimalNumber, string paramName);
/// <summary>
/// Check if this date is valid SQL date. Not all .NET dates are valid SQL dates.
/// </summary>
/// <param name="dateTime"></param>
void IsValidSqlDate(DateTime dateTime);
bool IsUri(string uriParamValue, string uriParamName);
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void DirectoryExists(string paramValue, string paramName);
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void CheckAzureTableName(string paramValue, string paramName);
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void CheckAzureTablePropertyValue(string paramValue, string paramName);
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void CheckAzureBlobContainerName(string paramValue, string paramName);
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void CheckAzureBlobName(string paramValue, string paramName);
void QueueName(string paramValue, string paramName);
/// <summary>
///
/// </summary>
/// <param name="paramValue"></param>
/// <param name="paramName"></param>
/// <exception cref="ArgumentException"></exception>
void CheckAzureDatabaseName(string paramValue, string paramName);
IbanValidationResult Iban(string paramValue);
}
public enum IbanValidationResult
{
IsValid,
ValueMissing,
ValueTooSmall,
ValueTooBig,
ValueFailsModule97Check,
CountryCodeNotKnown
}
}
//...
namespace Example.Implemented.Service
{
public class EntityService : IEntityService
{
public EntityService(
IValidationService validationService
)
{
_validationService = validationService;
}
public EntityFile AttachFileToEntity(string file, int entityId)
{
_validationService.StringIsNullOrEmpty(file, nameof(file));
_validationService.FileExists(file, nameof(file));
_validationService.EntityId(entityId, nameof(entityId));
}
}
}
@mrtarkhan
Copy link

hmmm, it's good at all, but you need to inject this service for all your services, "Don't Repeat Yourself"!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment