using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; using System.Net.Mail; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using AMWD.Common.Extensions; namespace System { /// /// String extensions. /// public static class StringExtensions { /// /// Converts a hex string into a byte array. /// /// The hex encoded string. /// A delimiter between the bytes (e.g. for MAC address). /// The bytes. public static IEnumerable HexToBytes(this string hexString, string delimiter = "") { if (string.IsNullOrWhiteSpace(hexString)) yield break; string str = string.IsNullOrEmpty(delimiter) ? hexString : hexString.Replace(delimiter, ""); if (str.Length % 2 == 1) yield break; if (Regex.IsMatch(str, "[^0-9a-fA-F]")) yield break; for (int i = 0; i < str.Length; i += 2) yield return Convert.ToByte(str.Substring(i, 2), 16); } /// /// Converts a byte collection into a hex string. /// /// The bytes. /// A delimiter to set between the bytes (e.g. for MAC address). /// The hex encoded string. public static string BytesToHex(this IEnumerable bytes, string delimiter = "") { if (bytes?.Any() != true) return null; return string.Join(delimiter, bytes.Select(b => b.ToString("x2"))); } /// /// Encodes a string to the hexadecimal system (base 16). /// /// The string to encode hexadecimal. /// The text encoding to use (default: ) /// public static string HexEncode(this string str, Encoding encoding = null) { if (string.IsNullOrEmpty(str)) return str; return (encoding ?? Encoding.Default).GetBytes(str).BytesToHex(); } /// /// Decodes a string from the hexadecimal system (base 16). /// /// The hexadecimal encoded string to decode. /// The text encoding to use (default: ) /// public static string HexDecode(this string str, Encoding encoding = null) { if (string.IsNullOrEmpty(str)) return str; return (encoding ?? Encoding.Default).GetString(str.HexToBytes().ToArray()); } /// /// Encodes a string to base64. /// /// The string to encode with base64. /// The text encoding to use (default: ) /// public static string Base64Encode(this string str, Encoding encoding = null) => Convert.ToBase64String((encoding ?? Encoding.Default).GetBytes(str)); /// /// Decodes a string from base64. /// /// The base64 encoded string to decode. /// The text encoding to use (default: ) /// public static string Base64Decode(this string str, Encoding encoding = null) => (encoding ?? Encoding.Default).GetString(Convert.FromBase64String(str)); /// /// Replaces the search substring with the replacement when it was found at the beginning of the string. /// /// The string. /// The searched substring. /// The replacement. /// public static string ReplaceStart(this string str, string search, string replacement) { if (str.StartsWith(search)) return replacement + str.Substring(search.Length); return str; } /// /// Replaces the search substring with the replacement when it was found at the end of the string. /// /// The string. /// The searched substring. /// The replacement. /// public static string ReplaceEnd(this string str, string search, string replacement) { if (str.EndsWith(search)) return str.Substring(0, str.Length - search.Length) + replacement; return str; } /// /// Parses a to a using culture "de" or invariant. /// /// The string to parse. /// public static decimal ParseDecimal(this string decString) { int dotIndex = decString.LastIndexOf('.'); int commaIndex = decString.LastIndexOf(','); var culture = dotIndex < commaIndex ? new CultureInfo("de-DE") : CultureInfo.InvariantCulture; return decimal.Parse(decString, culture); } /// /// Checks whether the given is a valid . /// /// /// You can enhance the check by requesting the MX record of the domain. /// /// The email address as string to validate. /// A value indicating whether to resolve a MX record (Google DNS is used). /// true when the email address is valid, other wise false. public static bool IsValidEmailAddress(this string email, bool checkForDnsRecord = false) => email.IsValidEmailAddress(checkForDnsRecord ? new[] { new IPEndPoint(IPAddress.Parse("8.8.8.8"), 53) } : null); /// /// Checks whether the given is a valid . /// /// /// The check is enhanced by a request for MX records on the defined . ///
/// The DNS resolution is only used when the DNS NuGet package is available. /// See: https://www.nuget.org/packages/DNS/7.0.0 ///
/// The email address as string to validate. /// A list of s of nameservers. /// true when the email address is valid, other wise false. public static bool IsValidEmailAddress(this string emailAddress, IEnumerable nameservers) { try { var mailAddress = new MailAddress(emailAddress); bool isValid = mailAddress.Address == emailAddress; if (isValid && nameservers?.Any() == true) { var dnsClientType = Type.GetType("DNS.Client.DnsClient, DNS"); if (dnsClientType == null) throw new DllNotFoundException("The DNS NuGet package is required: https://www.nuget.org/packages/DNS/7.0.0"); var recordTypeType = Type.GetType("DNS.Protocol.RecordType, DNS"); var resolveMethodInfo = dnsClientType.GetMethod("Resolve", new[] { typeof(string), recordTypeType, typeof(CancellationToken) }); bool exists = false; foreach (var nameserver in nameservers) { object dnsClient = Activator.CreateInstance(dnsClientType, new object[] { nameserver }); var waitTask = Task.Run(async () => await resolveMethodInfo.InvokeAsync(dnsClient, new object[] { mailAddress.Host, 15, CancellationToken.None })); // 15 = MX Record waitTask.Wait(); object response = waitTask.Result; waitTask.Dispose(); int responseCode = (int)response.GetType().GetProperty("ResponseCode").GetValue(response); if (responseCode != 0) continue; object list = response.GetType().GetProperty("AnswerRecords").GetValue(response); foreach (object item in (list as IEnumerable)) { int type = (int)item.GetType().GetProperty("Type").GetValue(item); if (type == 15) { exists = true; break; } } if (exists) break; } isValid &= exists; } return isValid; } catch { return false; } } /// /// Appends a copy of the specified string followed by the specified line terminator /// to the end of the current object. /// /// The object. /// The string to append. /// The line terminator. /// public static StringBuilder AppendLine(this StringBuilder sb, string value, string newLine) => sb.Append(value).Append(newLine); } }