I am pleased to announce the release (v2023.6.5.1) of Spargine on May 1st, 2022. Spargine is my open-source project and NuGet packages for .NET 6 & 7, which has been updated with new classes, methods, benchmarks, and unit tests. This release comes with speed improvements based on benchmark tests from the 3rd edition of “Rock Your Code: Code & App Performance for Microsoft .NET,” available on Amazon. These improvements have been implemented in all my projects, including many currently in production. I encourage you to explore these changes and provide feedback on what more you would like to see added.
GitHub: https://github.com/RealDotNetDave/dotNetTips.Spargine/releases
NuGet: http://bit.ly/dotNetDaveNuGet
You can find all the performance data for these assemblies on GitHub. I constantly seek assistance with these projects, particularly writing more unit tests. If you are interested in contributing, please feel free to contact me via email at dotnetdave@live.com.
Getting Processor Information
As part of an article I wrote, I discovered the GetSystemInfo
Windows API call that returns processor information that .NET does not. Here is an example of that data:
ActiveProcessorMask: 0x0000000000000fff
AllocationGranularity: 65536
MaximumApplicationAddress: 0x00007ffffffeffff
MinimumApplicationAddress: 0x0000000000010000
NumberOfProcessors: 12
PageSize: 4096
ProcessorArchitecture: X86
ProcessorLevel: 6
ProcessorRevision: 42243
To retrieve this information, I have added GetProcessorInformation()
to the App
type in DotNetTips.Spargine.6.Core assembly. Here is an example of how to use it:
var result = App.GetProcessorInformation();
Faster Logging
As part of an article I wrote about source generators to make logging faster. I have added these methods to EasyLoggerExtensions
in the DotNetTips.Spargine.6.Core assembly. Here is an example of one of those methods.
[LoggerMessage(EventId = 912, Level = LogLevel.Critical,
EventName = "CRITICAL", Message = "{methodName}: {message}.")]public static partial void LogCriticalMessage(this ILogger logger,
string message, Exception exception,
[CallerMemberName] string methodName = "");
This is how to use these methods.
logger.LogCriticalMessage(message: "Server is down!",
exception: argumentException);
The methods I’ve added are:
LogCriticalMessage()
LogDebugMessage()
LogErrorMessage()
LogExceptionMessage()
LogInformationMessage()
LogStoredProcedureError()
: Adds the stored procedure name to the error message.LogStoredProcedureNoRecordsFound()
LogTraceMessage()
LogWarningMessage()
I hope you will use these methods to log issues as fast as possible.
Making Regular Expressions Faster in .NET 7
After writing my article titled Performance: The Fastest Way to Use Regular Expressions in Microsoft .NET 7, I added a new class called RegexProcessor
. Below are the available methods.
ContainsWord()
: Return true of the text containing a word.IsCreditCardNumber()
: Returns true if the text is a valid credit card number.IsCurrencyCode()
: Returns true if the text is a 3-character currency code.IsEmailAddress()
: Returns true if the text is a valid email address.IsGuid()
: Returns true if the text is a valid Guid.IsISBN()
: Return true if the text is a valid ISBN (International Standard Book Number).IsUrl()
: Returns true if the text is a valid Url.ReplaceSpaces()
: Replaces spaces in a string with another string. Defaults to the “_” character.
New Enumerable Extensions
I’ve added the following extension methods for enumerables.
Parition<T>()
This method will partition a collection into a specified page count. Here is an example of how to use it.
IEnumerable<IEnumerable<Person>> splitPeople =
people.Partition(people.Count() / 10);
Split<T>()
This method will split a collection based on a page count. Here is an example of how to use it.
IEnumerable<IEnumerable<Person>> splitPeople =
people.Split(10);
New PreserveAttribute
When reviewing code for issues, I rely on the indicator in Visual Studio to determine whether a variable, method, or class is in use. However, there are instances where the reference count might be zero, but the code is still in use, such as when the object is set via dependency injection, the method is implemented due to a definition in an interface, or a method is overridden from a base class.
To make it easier to identify such cases and preserve the code, I have introduced a new attribute in DotNetTips.Spargine.6.Core called PreserveAttribute. By adding this attribute to a class, method, or variable, you can indicate that it should be preserved, even if the reference count is zero. Here is an example of how to use it:
[Preserve(preserveReason: PreserveReason.MethodOverride, reason: "Used by serialization.", createdOn: "05/01/2023", createdBy: "David McCarter")]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue(nameof(this.UserMessage), this.UserMessage);
}
Improvements to dotNetTips.Spargine.6.Tester
After writing an article, I started using a newer source generator for serializing JSON, which has improved performance. As part of this effort, I have created generators for the Person and PersonProper types, along with collections of those types. To demonstrate the usage of one of these types, consider the following example:
var json = RandomData.GeneratePersonRefCollection<PersonProper>(100).ToJson();
var result = JsonSerializer.Deserialize(json, PersonProperJsonSerializerContext.Default.ListPersonProper);
Using this generator does improve the performance when serializing and deserializing types!
Realistic Person and Address Information
This assembly previously created the person and address types with fake random data, that looks like this:
{
“Address1”: “GUdrKgQnkYoCnNP^E\u0060pyOBMWn”,
“Address2”: “\\xhrUMJJwrNqwSJtDcvwCoiCP”,
“Age”: “2190.00:00:00.1416747”,
“BornOn”: “2017-01-25T07:37:27.991408-08:00”,
“CellPhone”: “083-828-2338”,
“City”: “SgxDAn^LJdQaNPb”,
“Country”: “xakdRxHKlAvMMTV”,
“Email”: “cipgtdehgbj@gspyoepmpmxebawjnffyfo.org.uk”,
“FirstName”: “GKEavUf]DJGYxP^”,
“HomePhone”: “324-470-1840”,
“Id”: “ef719c98d4914b0abf62dc8f619bea14”,
“LastName”: “qyuQASb_IngAwpgyjuUNY\\QPW”,
“PostalCode”: “10557540”,
“State”: “cOctdg\u0060hHdsbVnt”
}
In this release, I have dedicated time to making the generated data appear more authentic. The methods responsible for generating the types now create all data, excluding Address1 and Address2, with random values that align with the person’s country. The generation process selects a random first name, last name, country, state, and city, and creates phone numbers and postal codes based on the selected country. As a result, the generated data now closely resembles actual data and appears as follows:
{
“Address1”: “yB[kEjKkUqcQLxG][odoUcIEy”,
“Address2”: “CnsfNH^tL_YWN^Fb[ca\\pfZFi”,
“BornOn”: “1957-04-09T16:08:45.8948496-07:00”,
“CellPhone”: “3140713855”,
“City”: “Floridsdorf”,
“Country”: “Austria”,
“Email”: “Courtney.Coronado@vemyy.shoes”,
“FirstName”: “Courtney”,
“HomePhone”: “0258058628”,
“Id”: “1c88785618f84e73b5e07172adb63f93”,
“LastName”: “Coronado”,
“PostalCode”: “5888”,
“State”: “Vienna”
}
I do plan to change Address1 and Address2 to more realistic data, but that is on the back burner for now.
This assembly holds data for all countries in the world along with its state and city data. If you need to use this information, simply call:
var countries = Countries.GetCountries();
These are the class models that will be returned.
Generate Fake Credit Card Numbers
I added a new method called GenerateCreditCard()
to generate a fake credit card number and GenerateCreditCards()
to create a collection of these numbers.
Generate Fake First and Last Names
I created a new method called GenerateFirstName()
that will return a random male or female name from a list of 1000 names. Also added GenerateLastName()
which will return a random last name from a list of 500 names.
Odds & Ends
Here are more features that were added for this release:
- Added an extension method called
IsEqualTo<T>
that determines if two lists are the same. - Added an extension method called
MillisecondsToString()
that converts milliseconds to hours, minutes, and seconds. This method is overloaded to accept long, int, and TimeSpan as input values. - Added extension method for arrays called
AddDistinct<T>()
that accepts an array and then ensures that the item isn’t already in the array before it’s added. - ApiLibraries: Class with constants for the common Windows API libraries. For example,
ApiLibraries.Kernel32
for the kernel32.dll. - New exception type called
NetworkConnectionException
. - New extension method for enumerable called
CountAsync<>()
. - New numeric extension methods called
Average()
for int32, decimal, int64, and double.
Summary
I trust that these methods in Spargine will be of greater utility to your projects. The benchmark results are available on GitHub, and you can access the links to them in the ReadMe file. If you require additional functionality, feel free to submit a pull request. I would love to hear your feedback and suggestions; kindly post them in the comments section below.
If you’re interested in enhancing your code performance, you may wish to explore my new book on the subject, available via this link: https://bit.ly/CodePerf3.
Keep coding geeks!