Coding Faster with dotNetTips Spargine – January 2022 Release

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.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.