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.
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 [email protected].
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.
- Towards(): 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.