I am happy to announce the fifth release (v2022.1.5.40) of Spargine on January 1st, 2022, my open-source projects, and NuGet packages for .NET 5 and above. I have added new classes, methods, benchmarks, and unit tests! I use these in all the projects I am currently working on including many that are in production! I hope you will check them out and let me know what you would like to see added.
GitHub: https://github.com/RealDotNetDave/dotNetTips.Spargine/releases
NuGet: http://bit.ly/dotNetDaveNuGet
This release includes performance changes too. All the performance data for these assemblies can be found on GitHub. I am always looking for help with these projects, especially writing more unit tests. If you would like to help, please email me at dotnetdave@live.com.
Hashing Passwords
Recently where I work, I was tasked with changing how the app hashes passwords since a third-party security team found that it was using an older method (MD5) that isn’t recommended anymore. On top of that, the company will be fined $15K if it does not comply! I set out to find out the better way to do it with .NET 5 & 6. Just a reminder, hashing is one way, it cannot be undone.
PBKDf2 Hash
In cryptography, PBKDF2 (Password-Based Key Derivation Function 2) are key derivation functions with a sliding computational cost, used to reduce vulnerabilities of brute-force attacks. I added the HashPasswordWithPBKDF2() method to EncryptionHelper. It’s very easy to use.
var password = EncryptionHelper.HashPasswordWithPBKDF2("H\\gFRUfbq_EMPlq"); Result: AY19M0MX0ANKDnG6yB3JIgHxHa7MWlO8aXEf7VD+hsD2B0LyFwBOJpUy7RhmflYYag==
Once the password is hashed, to validate it, use the VerifyPBKDF2HashedPassword() as shown below.
var result = EncryptionHelper.VerifyPBKDF2HashedPassword(hashedPassword, password);
This method returns a status of Failed, Success, and SuccessRehashNeeded.
SHA256 Hash
SHA-256 is a popular hashing algorithm used in Bitcoin encryption, first introduced when the network launched in 2009. Since then, SHA-256 has been adopted by several different blockchain projects, including several coins created from forks of the original Bitcoin source code. I added the HashPasswordWithSHA256() method to EncryptionHelper. It is also very easy to use.
var password = EncryptionHelper.HashPasswordWithSHA256("mHfVpo[wbvuYMal"); Result: AQAAAAAAAAAAAAAAAAAAAAC9sZ+PLwKAk4Vw5JAlOuY/GU4N6MNuMtT+Yj/ZfIPg7Q==
Just like the PBKDf2 hash, once the password is hashed, to validate it, use the VerifyPBKDF2HashedPassword() as shown below.
var result = EncryptionHelper.VerifySHA256HashedPassword(hashedPassword, password);
This method returns a status of Failed, Success and SuccessRehashNeeded.
Benchmark
The benchmark speed for these two methods is:
- HashPasswordWithPBKDF2 = 35,755.345 μs
- HashPasswordWithSHA256 = 1.735 μs
String Compression
In the System.IO.Compression namespace, there are methods to create zip files and compress strings. For this release of Spargine, I added methods that make it very easy to compress strings using GZip and Brotli.
GZip
GZip is a file format and a software application used for file compression and decompression. The program was created by Jean-loup Gailly and Mark Adler as a free software replacement for the compress program used in early Unix systems and intended for use by GNU.
GZip has the following compression levels:
- Fastest
- No Compression
- Optimal
I added the ToGZipAsync() and FromGZipAsync() to StringExtentions. Here is how you use them.
var result = await testValue.ToGZipAsync(CompressionLevel.Optimal); var result = compressedString.FromGZipAsync() Original string: ^w^vaBlKJ\\bNhvspfHfNTupWG Compressed string: H4sIAAAAAAAECgTBMQqAIAAAwHtbS2HgFLSIoIM0NAiSfd+77JdNxeZ1CpIqekxD1xya6PLpbrsFAAD//w==
Benchmark Results
Below are the benchmark results for this method using a string length of 10.
- Optimal = 439,930.407 ns
- Fastest = 9,291.633 ns
- NoCompression = 2,957.818 ns
Brotli
Brotli is a data format specification for data streams compressed with a specific combination of the general-purpose LZ77 lossless compression algorithm, Huffman coding, and 2nd order context modeling. Brotli is a compression algorithm developed by Google and works best for text compression.
Brotli has the following compression levels:
- Fastest
- No Compression
- Optimal
I added the To BrotliAsync() and FromBrotliAsync() to StringExtentions. Here is how you use them.
var result = await testValue.ToBrotliAsync(CompressionLevel.Optimal); var result = await compressedString.FromBrotliAsync()) Original string: QGhymbrMHsvbmVfQloPxv`csQ Compressed string: ixgA+I+UrOGddJv/qY/gHm9RiI4kKJAKgJIkpFjhguavOMK3o2xgbX3tCQ==
Benchmark Results
Below are the benchmark results for this method using a string length of 100.
- Optimal = 687,815.150 ns
- Fastest = 13,408.326 ns
- NoCompression = 3,542.519 ns
Validating String Length
There are many times when I need to validate a length of a string, usually when I write validation code for properties. There are multiple methods in StringExtentions to help with this. They are:
- HasValue(length): Checks for a string length.
- HasValue(minLength, maxLength): Checks to ensure a string length is within a specific length.
- HasValue(expression, RegexOptions): Checks a string using a regular expression.
- HasValue(string value): Checks a string to see if it contains a specific string using the ordinal string comparison.
Here is how I use HasValue() in Spargine:
var directory = key.GetValue<string>(UserFolderKey); if (directory.HasValue()) { // Code removed for brevity }
Validation of String Data Types
For a long time, I have needed and used code to check strings for a specific data type. For example, is the string an e-mail address? Is it an ISBN? Here are the methods in StringExtensions:
- IsAsciiDigit() (char)
- IsAsciiLetter() (char)
- IsAsciiLetterOrDigit() (char)
- IsAsciiWhitespace() (char)
- IsCreditCard()
- IsDomainAddress()
- IsEmailAddress()
- IsFirstLastName(): Determines whether the input contains a first and last name.
- IsGuid()
- IsISBN()
- IsMacAddress()
- IsScientific(): Determines whether the specified string is a scientific value.
- IsString(): Determines whether the string is valid.
- IsStringSHA1Hash()
- IsUrl()
Inspecting Your Types
If you need to get info about a type you are working with, Spargine has many methods to help with this. They are:
- DoesObjectImplementInferface()
- GetAllAbstractMethods()
- GetAllDeclaredFields()
- GetAllDeclaredMethods()
- GetAllFields()
- GetAllGenericMethods()
- GetAllMethods()
- GetAllProperties()
- GetAllPublicMethods()
- GetAllStaticMethods()
- GetAttribute<TAttribute>(): Get the attribute for a Type, MethodInfo, PropertyInfo, or FieldInfo.
- GetTypeMembersWithAttribute<TAttribute>()
- HasAttribute<TAttribute>
- HasBassClass()
- HasParameterlessConstructor()
- IsEnumerable(): Determines whether the type implements IEnumerable.
- IsNullable()
- IsStatic(): Determines whether the property is static.
Examples:
Here are some examples of these methods.
var table = new DataTable(); var result = table.DoesObjectImplementInterface("IComponent"); var result = typeof(Person).GetAllDeclaredFields(); Result: _address1, _address2, _bornOn, _cellPhone, _city, _country, _email, _firstName, _homePhone, _id, _lastName, _postalCode, _state var result = typeof(Person).GetAllDeclaredMethods(); Result: get_Address1, set_Address1, get_Address2, set_Address2, get_BornOn, set_BornOn, get_CellPhone, set_CellPhone, get_City, set_City, get_Country, set_Country, get_Email, set_Email, get_FirstName, set_FirstName, get_HomePhone, set_HomePhone, get_Id,set_Id, get_LastName, set_LastName, get_PostalCode, set_PostalCode, get_State, set_State, op_GreaterThanOrEqual, op_GreaterThan, op_Equality, op_LessThanOrEqual, op_LessThan, op_Inequality, CompareTo, Equals, Equals, GetHashCode, ToString, CalculateAge
Working With Numbers
The NumericExtensions in Spargine has many methods to validate numbers, format them, and more. Below are the methods.
- Decrement(): Decrement a number ensuring it never passes a given lower bound.
- EnsureMinimum()
- FormatSize(): Formats the number to size string.
- Increment(): Increment a number ensuring it never passes a given upper bound.
- IsEven()
- IsInRange(): Indicates whether the number falls in the specified range.
- IsInRangeThrowsException(): Determines whether [is in range throws exception] [the specified value]. Throws Exception if invalid.
- IsInterval()
- IsIntervalThrowsException(): Determines whether [is interval throws exception] [the specified value] and throws Exception if invalid.
- IsNegative()
- RoundToPowerOf2()
- ToFormattedString(): Converts number to a formatted string.
- ToPositiveValue()
- ToStringOrEmpty(): Parses the number to a string or a default string if outside the given range.
- ToWords(): Translate the number in words (English)
Examples
Here are a few examples on how to use these extension methods.
long testValue = 256234; var result = testValue.FormatSize(); Result: 250 KB var result = testValue.Increment(upperBound: 300000, step: 5); Result: 256239 int testValue = 54928; var result = testValue.ToWords(); Result: Fifty-Four Thousand Nine Hundred and Twenty-Eight
Some of these methods are documented in this post: http://bit.ly/SpargineFeb2021.
Even More New Code
I added new methods to convert IList<T> to different collection types:
- ToCollection(): Spargine collection.
- ToConcurrentHashSet(): Spargine collection.
- ToDistinctBlockingCollection(): Spargine collection.
- ToDistinctConcurrentBag(): Spargine collection.
- ToFastSortedList(): Spargine collection.
- ToImmutableArray()
- ToObservableList(): Spargine collection.
Breaking Changes
The following obsolete classes have been removed from dotNetTips.Spargine.5.Tester:
- IPersonPlus
- PersonFixed
- PersonPlus
Summary
I hope you will check out these methods or any of the others in the assemblies. I am also looking for contributors to these .NET projects. If you have any comments or suggestions, please comment below.