Last active
June 16, 2022 09:30
-
-
Save kdarty/156939609f8f7ba814fc to your computer and use it in GitHub Desktop.
A running list of helpful Extension Methods for C# projects.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Microsoft.Owin.Security; | |
| using System; | |
| using System.Collections.Generic; | |
| using System.ComponentModel; | |
| using System.ComponentModel.DataAnnotations; | |
| using System.Globalization; | |
| using System.IO; | |
| using System.Linq; | |
| using System.Linq.Expressions; | |
| using System.Net; | |
| using System.Reflection; | |
| using System.Runtime.InteropServices; | |
| using System.Security; | |
| using System.Security.Claims; | |
| using System.Security.Cryptography; | |
| using System.Security.Principal; | |
| using System.Text; | |
| using System.Text.RegularExpressions; | |
| using System.Web; | |
| using System.Web.Mvc; | |
| public static class ExtensionMethods | |
| { | |
| static readonly string _PasswordHash = "Add your own Hash Key here or read from Config"; | |
| static readonly string _SaltKey = "Add your Salt here or read from Config"; | |
| static readonly string _InitializationVector = "Add your 16 byte Initialization Vector (IV) here or read from Config"; | |
| public static Guid ToGuid(this int value) | |
| { | |
| byte[] bytes = new byte[16]; | |
| BitConverter.GetBytes(value).CopyTo(bytes, 0); | |
| return new Guid(bytes); | |
| } | |
| public static bool ToBoolean(this string value) | |
| { | |
| bool returnValue; | |
| bool.TryParse(value, out returnValue); | |
| return returnValue; | |
| } | |
| public static int ToInt(this Guid value) | |
| { | |
| byte[] b = value.ToByteArray(); | |
| int bint = BitConverter.ToInt32(b, 0); | |
| return bint; | |
| } | |
| public static int ToInt(this string value) | |
| { | |
| // Verify value is not NULL | |
| value = String.IsNullOrEmpty(value) ? "" : value; | |
| // If validation fails, Default return value to 0 | |
| int returnValue = 0; | |
| // Test if Integer, with or without comma separator | |
| Regex regex = new Regex(@"^(\d|,)*\d*$"); | |
| Match match = regex.Match(value); | |
| // If Valid Integer, Parse and Return Number | |
| if (match.Success) | |
| { | |
| // Strip out non-numeric characters | |
| string cleanValue = Regex.Replace(value, "[^0-9]+", ""); | |
| // Safely Parse to desired Data Type | |
| int.TryParse(cleanValue, out returnValue); | |
| } | |
| return returnValue; | |
| } | |
| public static double ToDouble(this string value, int? roundDigits = null) | |
| { | |
| // Verify value is not NULL | |
| value = String.IsNullOrEmpty(value) ? "" : value; | |
| double returnValue = 0.0D; | |
| // Test if Numeric with possible Currency, Thousands Separator and Decimals | |
| // RegEx Source: http://stackoverflow.com/questions/354044/what-is-the-best-u-s-currency-regex#answer-354276 | |
| Regex regex = new Regex(@"^\$?\-?([1-9]{1}[0-9]{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\-?\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\(\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))\)$"); | |
| Match match = regex.Match(value); | |
| if (match.Success) | |
| { | |
| // Strip out non-numeric characters | |
| string cleanValue = Regex.Replace(value, "[^0-9.]+", ""); | |
| // Safely Parse to desired Data Type | |
| double.TryParse(cleanValue, out returnValue); | |
| // Round the value if requested | |
| if (roundDigits.HasValue) | |
| { | |
| returnValue = Math.Round(returnValue, (int)roundDigits); | |
| } | |
| } | |
| return returnValue; | |
| } | |
| public static decimal ToDecimal(this string value, int? roundDigits = null) | |
| { | |
| // Verify value is not NULL | |
| value = String.IsNullOrEmpty(value) ? "" : value; | |
| decimal returnValue = 0.0M; | |
| // Test if Numeric with possible Currency, Thousands Separator and Decimals | |
| // RegEx Source: http://stackoverflow.com/questions/354044/what-is-the-best-u-s-currency-regex#answer-354276 | |
| Regex regex = new Regex(@"^\$?\-?([1-9]{1}[0-9]{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\-?\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))$|^\(\$?([1-9]{1}\d{0,2}(\,\d{3})*(\.\d{0,2})?|[1-9]{1}\d{0,}(\.\d{0,2})?|0(\.\d{0,2})?|(\.\d{1,2}))\)$"); | |
| Match match = regex.Match(value); | |
| if (match.Success) | |
| { | |
| // Strip out non-numeric characters | |
| string cleanValue = Regex.Replace(value, "[^0-9.]+", ""); | |
| // Safely Parse to desired Data Type | |
| decimal.TryParse(cleanValue, out returnValue); | |
| // Round the value if requested | |
| if (roundDigits.HasValue) | |
| { | |
| returnValue = Math.Round(returnValue, (int)roundDigits); | |
| } | |
| } | |
| return returnValue; | |
| } | |
| #region Date and Time Extension Methods | |
| /// <summary> | |
| /// Verify if given data is a valid Month | |
| /// </summary> | |
| /// <param name="value">Month to Test</param> | |
| /// <returns><see cref="bool"/></returns> | |
| public static bool IsValidMonth(this int value) | |
| { | |
| var validMonths = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; | |
| return (validMonths.Contains(value)); | |
| } | |
| /// <summary> | |
| /// Verify if given data is a valid Day | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Can optionally verify based on give Year and Month for more precision.</para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="value">Day to Test</param> | |
| /// <param name="month">Optional Month for more precise validation.</param> | |
| /// <param name="year">Optional Year for more precise validation.</param> | |
| /// <returns><see cref="bool"/></returns> | |
| public static bool IsValidDay(this int value, int? month = null, int? year = null) | |
| { | |
| // Default Maximum Days to 31 | |
| int maxDays = 31; | |
| if (month.HasValue && year.HasValue) | |
| { | |
| // Determine Valid Days in a given Month accounting for Leap Year | |
| maxDays = DateTime.DaysInMonth((int)year, (int)month); | |
| } | |
| // Validate given Value | |
| return (value >= 1 && value <= maxDays); | |
| } | |
| public static DateTime ToEasternTimeZone(this DateTime value) | |
| { | |
| TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); | |
| return TimeZoneInfo.ConvertTimeFromUtc(value, easternZone); | |
| } | |
| #endregion | |
| #region Credit Card Extension Methods | |
| /// <summary> | |
| /// Validate Credit Card Expiration Month | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Will determine if given Expiration Date is still valid based on today's Date</para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="month">Month to Test</param> | |
| /// <param name="year">Year to Test</param> | |
| /// <returns><see cref="bool"/></returns> | |
| public static bool IsValidExpirationMonth(this int month, int year) | |
| { | |
| var validMonths = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; | |
| if (validMonths.Contains(month) && year >= DateTime.Now.Year) | |
| { | |
| DateTime expiration = new DateTime(year, month, 1); | |
| return expiration >= DateTime.Now; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| } | |
| #endregion | |
| #region Secure String Extension Methods | |
| /// <summary> | |
| /// Returns an Insecure String from the SecureString Source Data | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Source: http://stackoverflow.com/questions/9887996/how-to-convert-a-string-to-securestring-explicitly#answer-31491863</para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="secureString"><see cref="SecureString"/> Data</param> | |
| /// <returns>Insecure <see cref="String"/></returns> | |
| public static string ToUnsecureString(this SecureString secureString) | |
| { | |
| if (secureString == null) | |
| { | |
| return null; | |
| } | |
| else | |
| { | |
| var unmanagedString = IntPtr.Zero; | |
| try | |
| { | |
| unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secureString); | |
| return Marshal.PtrToStringUni(unmanagedString); | |
| } | |
| finally | |
| { | |
| Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Returns a Secure String from the Source String | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Source: http://stackoverflow.com/questions/9887996/how-to-convert-a-string-to-securestring-explicitly#answer-31491863</para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="unsecureString">Non-Secure String</param> | |
| /// <returns><see cref="SecureString"/></returns> | |
| public static SecureString ToSecureString(this string unsecureString) | |
| { | |
| if (string.IsNullOrWhiteSpace(unsecureString)) | |
| { | |
| return null; | |
| } | |
| else | |
| { | |
| return unsecureString.Aggregate(new SecureString(), AppendChar, MakeReadOnly); | |
| } | |
| } | |
| /// <summary> | |
| /// Helper Method to Make a SecureString object Read Only | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Source: http://stackoverflow.com/questions/9887996/how-to-convert-a-string-to-securestring-explicitly#answer-31491863</para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="secureString"><see cref="SecureString"/> Source Object</param> | |
| /// <returns>Read Only <see cref="SecureString"/></returns> | |
| private static SecureString MakeReadOnly(SecureString secureString) | |
| { | |
| secureString.MakeReadOnly(); | |
| return secureString; | |
| } | |
| /// <summary> | |
| /// Helper Method used when Creating a SecureString from an Insecure String | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Source: http://stackoverflow.com/questions/9887996/how-to-convert-a-string-to-securestring-explicitly#answer-31491863</para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="secureChar"><see cref="SecureString"/></param> | |
| /// <param name="c">Character Value</param> | |
| /// <returns><see cref="SecureString"/> version of supplied Character</returns> | |
| private static SecureString AppendChar(SecureString secureChar, char c) | |
| { | |
| secureChar.AppendChar(c); | |
| return secureChar; | |
| } | |
| /// <summary> | |
| /// Add or Update Claims based on given Security Principal | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Usage: <code>User.AddUpdateClaim("key1", "value");</code></para> | |
| /// <para>If the Value given is NULL the code will silently ignore and add nothing.</para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="currentPrincipal"></param> | |
| /// <param name="key"></param> | |
| /// <param name="value"></param> | |
| public static void AddUpdateClaim(this IPrincipal currentPrincipal, string key, string value) | |
| { | |
| var identity = currentPrincipal.Identity as ClaimsIdentity; | |
| if (identity == null) | |
| return; | |
| // Check for Existing Claim and Remove it | |
| var existingClaim = identity.FindFirst(key); | |
| if (existingClaim != null) | |
| identity.RemoveClaim(existingClaim); | |
| // Add New Claim | |
| if (value != null) | |
| { | |
| identity.AddClaim(new Claim(key, value)); | |
| var authenticationManager = HttpContext.Current.GetOwinContext().Authentication; | |
| authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true }); | |
| } | |
| } | |
| /// <summary> | |
| /// Get a given Claim Value from a given Security Principal | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Usage: <code>var key1 = User.GetClaim("key1");</code></para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="currentPrincipal"></param> | |
| /// <param name="key"></param> | |
| /// <returns></returns> | |
| public static string GetClaimValue(this IPrincipal currentPrincipal, string key) | |
| { | |
| var identity = currentPrincipal.Identity as ClaimsIdentity; | |
| if (identity == null) | |
| return null; | |
| // Attempt to Retrieve Claim Value | |
| string claimValue = identity.Claims.Where(claim => claim.Type == key) | |
| .Select(claim => claim.Value).SingleOrDefault(); | |
| return claimValue; | |
| } | |
| #endregion | |
| /// <summary> | |
| /// Remove all elements of an Object Model from ModelState | |
| /// <remarks> | |
| /// <para>This is helpful for removing Optional Object Models from a ViewModel before processing.</para> | |
| /// <para>See <a href="http://stackoverflow.com/questions/6843171/is-it-correct-way-to-use-modelstate-remove-to-deal-with-modelstate">Stackoverflow Discussion here</a></para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <typeparam name="TModel"></typeparam> | |
| /// <param name="modelState"></param> | |
| /// <param name="expression"></param> | |
| public static void RemoveFor<TModel>(this ModelStateDictionary modelState, | |
| Expression<Func<TModel, object>> expression) | |
| { | |
| string expressionText = ExpressionHelper.GetExpressionText(expression); | |
| foreach (var ms in modelState.ToArray()) | |
| { | |
| if (ms.Key.StartsWith(expressionText + ".") || ms.Key == expressionText) | |
| { | |
| modelState.Remove(ms); | |
| } | |
| } | |
| } | |
| #region List and Collection Extension Methods | |
| public static SelectList ToSelectList<TEnum>(this TEnum enumObj) | |
| where TEnum : struct, IComparable, IFormattable, IConvertible | |
| { | |
| var values = from TEnum e in Enum.GetValues(typeof(TEnum)) | |
| select new { Id = e, Name = e.ToString() }; | |
| return new SelectList(values, "Id", "Name", enumObj); | |
| } | |
| /// <summary> | |
| /// Extension Metion to verify that a Generic List is not NULL or Empty | |
| /// </summary> | |
| /// <typeparam name="T">List Type</typeparam> | |
| /// <param name="source"><see cref="List"/> Source</param> | |
| /// <returns><see cref="bool"/> (true/false)</returns> | |
| public static bool IsNullOrEmpty<T>(this List<T> source) | |
| { | |
| if (source != null && source.Any()) | |
| { | |
| return false; | |
| } | |
| else | |
| { | |
| return true; | |
| } | |
| } | |
| /// <summary> | |
| /// Extension Method to verify that a Generic IEnumerable is not NULL or Empty | |
| /// </summary> | |
| /// <typeparam name="T">IEnumerable Type</typeparam> | |
| /// <param name="source"><see cref="IEnumerable"/> Source</param> | |
| /// <returns><see cref="bool"/> (true/false)</returns> | |
| public static bool IsNullOrEmpty<T>(this IEnumerable<T> source) | |
| { | |
| if (source != null && source.Any()) | |
| { | |
| return false; | |
| } | |
| else | |
| { | |
| return true; | |
| } | |
| } | |
| /// <summary> | |
| /// Extension Method to Add an Item to an <see cref="IEnumerable{T}"/> | |
| /// </summary> | |
| /// <typeparam name="T">Data Type of the <see cref="IEnumerable{T}"/> </typeparam> | |
| /// <param name="e"></param> | |
| /// <param name="value">Object Value to Add</param> | |
| /// <returns>An updated version of the source IEnumerable</returns> | |
| public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) | |
| { | |
| foreach (var cur in e) | |
| { | |
| yield return cur; | |
| } | |
| yield return value; | |
| } | |
| #endregion | |
| /// <summary> | |
| /// Verify if a Nullable INT is NULL or has a given Value | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Useful for testing if NULL or 0</para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="value">Nullable <see cref="int"/> Source Object</param> | |
| /// <param name="valueToCheck">Value to Check</param> | |
| /// <returns><see cref="bool"/> True/False</returns> | |
| public static bool IsNullOrValue(this int? value, int valueToCheck) | |
| { | |
| return (value ?? valueToCheck) == valueToCheck; | |
| } | |
| /// <summary> | |
| /// Verify if Nullable Double is NULL or has a given Value | |
| /// <remarks> | |
| /// <para> </para> | |
| /// <para>Useful for testing if NULL or 0</para> | |
| /// </remarks> | |
| /// </summary> | |
| /// <param name="value">Nullable <see cref="double"/> Source Object</param> | |
| /// <param name="valueToCheck">Value to Check</param> | |
| /// <returns><see cref="bool"/> True/False</returns> | |
| public static bool IsNullOrValue(this double? value, double valueToCheck) | |
| { | |
| return (value ?? valueToCheck) == valueToCheck; | |
| } | |
| /// <summary> | |
| /// Retrieve the Description of a given Enum | |
| /// </summary> | |
| /// <param name="value"><see cref="Enum"/> Source Object</param> | |
| /// <returns><see cref="String"/> Description</returns> | |
| public static string GetDescription(this Enum value) | |
| { | |
| if (value == null) | |
| { | |
| throw new ArgumentNullException("value"); | |
| } | |
| string desc = value.ToString(); | |
| FieldInfo info = value.GetType().GetField(desc); | |
| var attrs = (DescriptionAttribute[])info.GetCustomAttributes(typeof(DescriptionAttribute), false); | |
| if (attrs != null && attrs.Length > 0) | |
| { | |
| desc = attrs[0].Description; | |
| } | |
| return desc; | |
| } | |
| #region String Type Extensions | |
| public static string Encrypt(this string plainText) | |
| { | |
| // Check for Null String | |
| plainText = (string.IsNullOrWhiteSpace(plainText)) ? string.Empty : plainText; | |
| byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); | |
| byte[] keyBytes = new Rfc2898DeriveBytes(_PasswordHash, Encoding.ASCII.GetBytes(_SaltKey)).GetBytes(256 / 8); | |
| var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros }; | |
| var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(_InitializationVector)); | |
| byte[] cipherTextBytes; | |
| using (var memoryStream = new MemoryStream()) | |
| { | |
| using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) | |
| { | |
| cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); | |
| cryptoStream.FlushFinalBlock(); | |
| cipherTextBytes = memoryStream.ToArray(); | |
| cryptoStream.Close(); | |
| } | |
| memoryStream.Close(); | |
| } | |
| return Convert.ToBase64String(cipherTextBytes); | |
| } | |
| public static string Decrypt(this string encryptedText) | |
| { | |
| // Check for Null String | |
| encryptedText = (string.IsNullOrWhiteSpace(encryptedText)) ? string.Empty : encryptedText; | |
| byte[] cipherTextBytes = Convert.FromBase64String(encryptedText); | |
| byte[] keyBytes = new Rfc2898DeriveBytes(_PasswordHash, Encoding.ASCII.GetBytes(_SaltKey)).GetBytes(256 / 8); | |
| var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None }; | |
| var decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(_InitializationVector)); | |
| var memoryStream = new MemoryStream(cipherTextBytes); | |
| var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read); | |
| byte[] plainTextBytes = new byte[cipherTextBytes.Length]; | |
| int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); | |
| memoryStream.Close(); | |
| cryptoStream.Close(); | |
| return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray()); | |
| } | |
| public static bool IsInteger(this string source) | |
| { | |
| int test; | |
| return int.TryParse(source, out test); | |
| } | |
| public static bool IsDouble(this string source) | |
| { | |
| double test; | |
| return double.TryParse(source, out test); | |
| } | |
| #endregion | |
| #region Enumerations Extension Methods | |
| public static string GetDescription<T>(this T e) where T : IConvertible | |
| { | |
| string description = null; | |
| if (e is Enum) | |
| { | |
| Type type = e.GetType(); | |
| Array values = System.Enum.GetValues(type); | |
| foreach (int val in values) | |
| { | |
| if (val == e.ToInt32(CultureInfo.InvariantCulture)) | |
| { | |
| var memInfo = type.GetMember(type.GetEnumName(val)); | |
| var descriptionAttributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false); | |
| if (descriptionAttributes.Length > 0) | |
| { | |
| // we're only getting the first description we find | |
| // others will be ignored | |
| description = ((DescriptionAttribute)descriptionAttributes[0]).Description; | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| return description; | |
| } | |
| #endregion | |
| public static string RelativePath(this HttpServerUtilityBase srv, string path, HttpRequestBase context) | |
| { | |
| return path.Replace(context.ServerVariables["APPL_PHYSICAL_PATH"], string.Empty).Replace(@"\", "/"); | |
| } | |
| public static bool IsHtml(this string source) | |
| { | |
| return Regex.IsMatch(source, @"/<[a-z][\s\S]*>/"); | |
| } | |
| /// <summary> | |
| /// Use the current thread's culture info for conversion | |
| /// </summary> | |
| public static string ToTitleCase(this string source) | |
| { | |
| var cultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture; | |
| return cultureInfo.TextInfo.ToTitleCase(source.ToLower()); | |
| } | |
| /// <summary> | |
| /// Overload which uses the culture info with the specified name | |
| /// </summary> | |
| public static string ToTitleCase(this string source, string cultureInfoName) | |
| { | |
| var cultureInfo = new CultureInfo(cultureInfoName); | |
| return cultureInfo.TextInfo.ToTitleCase(source.ToLower()); | |
| } | |
| /// <summary> | |
| /// Overload which uses the specified culture info | |
| /// </summary> | |
| public static string ToTitleCase(this string source, CultureInfo cultureInfo) | |
| { | |
| return cultureInfo.TextInfo.ToTitleCase(source.ToLower()); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment