Coding Faster With .NetTips Spargine - June 2021 Release

I am happy to announce the third release (v2021.6.3.5) of Spargine, my brand new open-source projects, and NuGet packages for .NET 5 and above. I have added new classes, methods, and unit tests! I use these in all the projects I am currently working on including some that are in production! I hope you will check them out and let me know what you would like to see added.

Retrieving Application Information

I have a class called App.cs that is designed to return information about the currently running app. I use it all the time since this info seems to be spread around the .NET Framework (CLR), Core, and .NET. Here are just some of the methods in this class.

AppInfo()

This method returns specific information about the currently running app such as,

  • Company: "Microsoft Corporation"
  • Copyright: "© Microsoft Corporation. All rights reserved."
  • EqualityContract: FullName = "dotNetTips.Spargine.Core.AppInfo", DomainInitialized = Method System.RuntimeType.get_DomainInitialized cannot be called in this context.
  • FileVersion: "15.0.0"
  • MemoryAllocated: 1720944
  • MemoryInfo: {System.GCMemoryInfo}
  • Product: "dotNetTips.Spargine"
  • ThreadAllocatedBytes: 745384
  • Title: "Spargine"
  • TotalAllocatedBytes: 3169744
  • Version: "16.9.1"

GetEnvornmentVariables()

This returns the current environment variables which are used a lot when programming. Here is an example (from my Surface laptop),

  • [0]: {[CommonProgramFiles(x86), C:\Program Files (x86)\Common Files]}
  • [1]: {[SESSIONNAME, Console]}
  • [2]: {[VisualStudioEdition, Microsoft Visual Studio Enterprise 2019]}
  • [3]: {[Path, C:\WINDOWS\system32; C:\WINDOWS; C:\WINDOWS\System32\Wbem; C:\WINDOWS\System32\WindowsPowerShell\v1.0\; C:\WINDOWS\System32\OpenSSH\; C:\Program Files\dotnet\; C:\Program Files\Microsoft SQL Server\130\Tools\Binn\; C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\; C:\Program Files\nodejs\; C:\Program Files (x86)\dotnet\;]}
  • [4]: {[VisualStudioDir, C:\Users\dotNetDave\Documents\Visual Studio 2019]}
  • [5]: {[NUMBER_OF_PROCESSORS, 4]}
  • [6]: {[COMPLUS_NoGuiFromShim, 1]}
  • [7]: {[APPDATA, C:\Users\dotNetDave\AppData\Roaming]}
  • [8]: {[COMPUTERNAME, DESKTOP-AAA12345BC]}
  • [9]: {[USERDOMAIN_ROAMINGPROFILE, DESKTOP-AAA12345BC]}
  • [10]: {[VSLS_SESSION_KEEPALIVE_INTERVAL, 0]}
  • [11]: {[CommonProgramFiles, C:\Program Files\Common Files]}
  • [12]: {[VSLOGGER_UNIQUEID, b24dccbdefd044c092cdaef70f80d188]}
  • [13]: {[ProgramFiles(x86), C:\Program Files (x86)]}
  • [14]: {[SystemRoot, C:\WINDOWS]}
  • [15]: {[USERPROFILE, C:\Users\dotNetDave]}
  • [16]: {[TEMP, C:\Users\dotNetDave\AppData\Local\Temp]}
  • [17]: {[PROCESSOR_LEVEL, 6]}
  • [18]: {[ALLUSERSPROFILE, C:\ProgramData]}
  • [19]: {[LOGONSERVER, \\DESKTOP-AAA12345BC]}
  • [20]: {[OneDriveCommercial, C:\Users\dotNetDave\OneDrive - dotNetTips.com]}
  • [21]: {[DriverData, C:\Windows\System32\Drivers\DriverData]}
  • [22]: {[PROCESSOR_REVISION, 8e09]}
  • [23]: {[PSModulePath, C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules]}
  • [24]: {[ThreadedWaitDialogDpiContext, -4]}
  • [25]: {[ProgramFiles, C:\Program Files]}

ReferencedAssemblies()

This method returns all the assemblies that the app is using,

  • [0]: "System.Runtime, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [1]: "System.Resources.ResourceManager, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [2]: "System.Runtime.InteropServices, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [3]: "Microsoft.TestPlatform.PlatformAbstractions, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [4]: "Microsoft.TestPlatform.CommunicationUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [5]: "Microsoft.TestPlatform.CoreUtilities, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [6]: "Microsoft.VisualStudio.TestPlatform.Common, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [7]: "Microsoft.VisualStudio.TestPlatform.ObjectModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [8]: "System.Diagnostics.TraceSource, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [9]: "System.Diagnostics.StackTrace, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [10]: "System.Runtime.Extensions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [11]: "System.Diagnostics.Debug, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [12]: "Microsoft.TestPlatform.CrossPlatEngine, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [13]: "System.Net.Primitives, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [14]: "System.Runtime.InteropServices.RuntimeInformation, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  • [15]: "System.Linq, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

Other Methods

  • ChangeCulture()
  • ChangeUICulture()
  • ExecutingFolder(): Returns the folder the application is running from.
  • FrameworkDescription(): Example output: ".NET 5.0.6"
  • GetCulture()
  • GetUICulture()
  • IsRunningFromAspNet()
  • IsUserAdministrator()
  • OSArchitecture()
  • OSDescription()
  • ProcessArchitecture()
  • StackTrace()
  • WorkingSet()

Adding Add()/ AddIf() & Upsert() To Collections

For this release, I decided to make sure all my collection extension classes include the methods Add(), AddIf(), and Upsert() to make them consistent. They all are very easy to use, and I hope you start using them too.

Add()

This method will add the item to the last position in the collection. In the case of arrays, this method will return the new array that is not needed for the other collection types.

PersonProper[] result = people.Add(person);

AddIf()

AddIf() will only add the item if the Boolean statement is true.

people.AddIf(person, people.Count() == 10);

Upsert()

This method will either insert or update the item, just like if you are updating CosmosDB.

people.Upsert(newPerson.Id, newPerson);

For Dictionary collections this is overloaded and the easiest to use if the items in your collection inherit from IDataModel.

DriveHelper

I have added the DriveHelper method from the .NET Core codebase. Here are some of the methods in this class.

GetFixedDrives()

This method returns all the fixed drives on the computer as a collection of DriveInfo.

var result = DriveHelper.GetFixedDrives();

GetRemoveableDrives()

This method returns all the removable drives connected to the computer as a collection of DriveInfo.

var result = DriveHelper.GetRemovableDrives();

FileHelper

I have added the FileHelper class from the .NET Core codebase. Here are some of the methods in this class.

CopyFile()

This method copies the file to a new directory. If the file already exists, it will be overwritten.

var result = FileHelper.CopyFile(file: fileToCopy, destinationFolder: this._tempPath);

This method returns the length of the file. The parameters for this method using FileInfo for the file and DirectoryInfo for the destination folder.

DeleteFiles()

This method attempts to delete files and will return the file name and error message for files that could not be deleted.

var result = FileHelper.DeleteFiles(filesToDelete);

DownloadFileFromWeb()

This method downloads the file from the web and stores it in the given local file path. I use this method in my free app for .NET software engineers.

const string fileToDownload = @"https://dotnettips.files.wordpress.com/dotnettips-com-logo05x1.png";
FileHelper.DownloadFileFromWeb(new Uri(fileToDownload), Path.Combine(this._tempPath.FullName, "dotNetTips.Com.logo.png"));

There is also an async version of this method too. There is also DownloadFileFromWebAndUnzipAsync() which does the same thing as DownloadFileFromWeb(), but it is for files that have been zipped and will un-zip it for you!

MoveFile()

This method moves a file from one location to another. The added value of this method is that if there is an IOException or UnauthorizedAccessExeption, it will try again for 9 more times. There are two MoveFile() methods where the second one allows you to choose how the file will be overwritten. Those choices are,

  1. Replace the existing file
    If the destination file exists, the function replaces its contents with the contents of the existing file, if security requirements regarding access control lists (ACLs) are met.
     
  2. Copy allowed
    If the file is to be moved to a different volume if the file is successfully copied to a different volume and the original file is unable to be deleted, the function succeeds leaving the source file intact.
     
  3. Delay until reboot
    The system does not move the file until the operating system is restarted. The system moves the file immediately after AUTOCHK is executed, but before creating any paging files. Consequently, this parameter enables the function to delete paging files from previous startups. This value can be used only if the process is in the context of a user who belongs to the administrator’s group or the LocalSystem account.
     
  4. Fail if not trackable
    The function fails if the source file is a link source, but the file cannot be tracked after the move. This situation can occur if the destination is a volume formatted with the FAT file system.
     
  5. Write through
    The function does not return until the file is moved on the disk. Setting this value guarantees that a move performed as a copy and delete operation is flushed to the disk before the function returns. The flush occurs at the end of the copy operation.

Here is how to use this method.

FileHelper.MoveFile(file, newFile, FileMoveOptions.ReplaceExisting);

Other Methods

Other methods in FileHelper include,

  1. UnGZipAsync()
    Un-GZips a file as an asynchronous operation.
     
  2. UnZipAsync()
    Un-zips a file as an asynchronous operation.
     
  3. UnWinZipsAsync()
    Un-WinZips a file as an asynchronous operation.

FileProcessor

The FileProcess class has methods such as CopyFiles(), DeleteFiles() and DeleteFolders() that uses events to show progress! I use this class in my free app for .NET software engineers.

CopyFiles()

This method copies a collection of files as FileInfo and sends a progress event on success and errors.

processor.Processed += this.Processor_Processed;
processor.CopyFiles(files: files, destinationFolder: new DirectoryInfo(Path.GetTempPath()));
private void Processor_Processed(object sender, FileProgressEventArgs e) {
    Debug.WriteLine(e.Message);
}

DeleteFiles()

This method deletes a collection of files as FileInfo and sends progress events on success and errors.

DeleteFolders()

This method deletes a collection of folders as DirectoryInfo and sends progress events on success and errors.

PathHelper

The PathHelper class has methods to deal with file paths for Windows. Below are some of those methods.

CombinePaths()

This method allows you to create a path from a collection of paths. The method in .NET only does two at a time.

var basePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var paths = new string[] { basePath, "Test1", "Test2", "Test3" };
var tempPath = PathHelper.CombinePaths(createIfNotExists: true, paths: paths);

This method has three overloads. Other methods include,

  • EnsureTrailingSlash()
    This method makes sure your path has a backslash at the end of it.
     
  • HasInvalidFilterChars()
    This method makes sure that a file search filter does not have these characters: *, | and ?.
     
  • InvalidPathNameChars()
    This property returns characters not allowed in path names. There are 33 invalid characters.
     
  • PathContainsWildcare()
    This method returns true if the path contains the illegal character *.
     
  • PathHasInvalidChars()
    This method determines if the path has any illegal characters.
     
  • PathSeparators()
    This property returns allowed path separators.

Services

Many times, in my carrier and my free app for .NET software engineers, I need to start and stop Windows services. The Services class had the following methods,

  • AllServices()
    This returns a list of all the services currently on the system. When I wrote this article, I have 282 services! Here are just some of them: AdobeARMservice, AdobeUpdateService, AGMService, AGSService, DispBrokerDesktopSvc, DisplayEnhancementService, DmEnrollmentSvc, dmwappushservice, Dnscache, DoSvc, dot3svc, DPS, DsmSvc, DsSvc, DusmSvc, Eaphost, edgeupdate, edgeupdatem, EFS, embeddedmode, EntAppSvc, esifsvc, EventLog, EventSystem, Fax, fdPHost, FDResPub, fhsvc, FontCache, FontCache3.0.0.0, FrameServer
     
  • ServiceExists()
    Checks to see if service exists on the system.
     
  • ServiceStatus()
    Checks the service status. It will return Stopped, StartPending, StopPending, Running, ContinuePending, PausePending, and Paused.
     
  • StartService()
    This method will start a service and return one of these values: NotFound, Running, Stopped, or Error.
     
  • StartServices()
    This method will attempt to start multiple services with one call.
     
  • StartStopServices()
    This method will attempt to start or stop multiple services with one call.
     
  • StopService()
    This method will attempt to stop the service.
     
  • StopServices()
    This method will attempt to stop multiple services with one call.

KeyGenerator

I moved the unique key generation code from the Tester project to the Core project. It has a method called GenerateKey() that can be used with IDs, even for CosmosDB. It returns a key like this: f7f0af78003d4ab194b5a4024d02112a. It is also overloaded so you can add a prefix to the key.

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 5 projects. If you have any comments or suggestions, please comment below.


Similar Articles
McCarter Consulting
Software architecture, code & app performance, code quality, Microsoft .NET & mentoring. Available!