Moonrise.StandardUtils.NetStd 4.2020.1211.13060

There is a newer version of this package available.
See the version list below for details.
dotnet add package Moonrise.StandardUtils.NetStd --version 4.2020.1211.13060
NuGet\Install-Package Moonrise.StandardUtils.NetStd -Version 4.2020.1211.13060
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Moonrise.StandardUtils.NetStd" Version="4.2020.1211.13060" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Moonrise.StandardUtils.NetStd --version 4.2020.1211.13060
#r "nuget: Moonrise.StandardUtils.NetStd, 4.2020.1211.13060"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Moonrise.StandardUtils.NetStd as a Cake Addin
#addin nuget:?package=Moonrise.StandardUtils.NetStd&version=4.2020.1211.13060

// Install Moonrise.StandardUtils.NetStd as a Cake Tool
#tool nuget:?package=Moonrise.StandardUtils.NetStd&version=4.2020.1211.13060

Moonrise.StandardUtils.NetStd

A collection of really useful little classes and extension methods that I've accumulated over the years.

Config.Settings

Settings will work with either JSON (by default) or XML configuration files. It is far less faff than using the "built-in" way, provides the ability to write out settings that haven't yet been created, works with both application and user settings and provides fully transparent machine or user level encryption.It is fully thread-safe. You don't need any of the Microsoft infrastructure to use this - though you can still use it side-by-side as it simply reads the config file - so it's great for all application types.

Usage

    internal class MyConfigClass
    {
        public int AnInt { get; set; } = 42;
        public LoggingLevel LoggingLevel { get; set; } = LoggingLevel.Debug;
        public string AString { get; set; } = "Initial Value";
        public AnotherConfigClass AdditionalConfig { get; set; } = new AdditionalConfig();
    }
    ...
    MyConfigClass Config;
    ...
    // Read the config into the instance of the config class. The (optional) true param says, if that setting is not there, then write it in.
    Settings.Application.Read("MyConfigLocation", ref Config, true);

Initialisation

By default Settings will use a JsonConfigSettingsProvider, which by default uses an appSettings.json file, so unless you need to override anything, just using Settings.Application or Settings.User "out of the box" will just work.

Opinion

I do not like the concept of injecting a settings object into different classes as Microsoft seem to encourage. Why? I believe that breaks the SRP (Single Responsibility Principal). I believe that a class should define its "data requirements" and be passed that data. It shouldn't be left for that class to pull its initialisation data out of a particular store. What if you want to store your config in a database? What if you want it to be dynamic?

What I do for my startup code is create a collated configuration class that uses nested configuration for all of the configuration anything needs to get from settings, read it all in one shot and where that config is required for any DI constructed classes register the config appropriately. Now when you come to test, you don't need to faff about with different settings files or mocked settings providers, just give the class under test the data it wants.

User Settings

Instead of Settings.Application just use Settings.User. The settings file will be located in the user's app data folder.

Encryption

Settings can make use an encryption provider to decrypt an encrypt settings, either in a group or individually. The supplied DpApiSettingsEncryptor makes use of the Data Protection API to encrypt or decrypt using the keys in either the User or Machine store. Since Settings can be written there is an option to write them as encrypted, these will then be passed through the encryption provider to encrypt. There is a command-line utility EncryptAppSettings.exe that is bundled in the Moonrise.Samples Nuget package - you'll need to dig into the package folder in your cache. Encrypted data is written as Base64 between a start marker of "[{ENC]{" and an end marker of "]{ENC[{" - chosen for the extreme unlikelihood of those sets of characters occurring naturally in a settings file.

Using the DpApiSettingsEncryptor (as used by the afore-mentioned .exe) means you either encrypt using User or Machine level stores. User level means the encrypted settings can only be read by processes running under that user account but can be done so on any machine. Machine level means the encrypted settings can only be read on the machine that did the encryption.

DateTime Providers

An interfaced DateTime/Offset provider that supplies a .Now that you can control, particularly for testing.

Reasoned Exceptions

I REALLY like these. A ReasonedException<TEnumReason> is an exception that is only ever created with an enum "Reason". The enum is given a [Description(description text)] which becomes the text message for the exception and will often include {0} {1} {etc} placeholders so that when it comes to throw that exception, you pass the variables appropriately and you've got a well though out reason for throwing your exception. You also get a list of all the reasons this exception may be thrown, by virtue of the enums. If you then additionally use XML comments for the enum members that completely matches your [Description(description text)] you will get Intellisense at the point where the exception is thrown giving you the text. This pattern/approach means you have very tight control over the exceptions that you throw. You have defined reasons and controlled text so that you are not making up potentially different messages for the same reason.

Extensions

A bunch of useful extension methods

DateTime/OffsetExtensions

.Within() - Is the DateTime/Offset within the last few X of now - Seconds, Minutes, Years etc.

.TrimOff() - Truncates a DateTime/Offset to the required unit.

EnumExtensions

.Description() - gives the description of an enum as defined by its, in this order, changed description (see later), [Description] or string value (which for PascalCased values will be "Pascal Cased").

.ModifyDescription() - allows you to effectively modify the description attribute. I've used this in internationalisation, reading values from a database and updating the enum description.

StringExtensions

.CSL() - gives a Comma (actually any string you want) Separated List from an IEnumerable - OK, not strictly a string extension!

.Extract() - extracts a string from a string between two specified strings at a particular starting point. Great for ad-hoc parsing.

.Left()/Mid()/Right() - gets substrings to the left middle or right of a string.

.Pluralise() - Pretty good pluraliser that can include counts and use a custom plural string.

.ReplaceBetween() - Replaces one string with another between two sets of strings.

Threading

ScopedNestableThreadGlobalSingleton<T>

Provides scoped, nestable, thread global values.

Scoped because any call to get the value (via a static) that occurs somewhere INSIDE the using scope will get that value.

Nestable because if you open another scope (through an interior/nested using) then THAT becomes the value anything inside of THAT scope will receive whereas once outside of THAT using scope the value for the PREVIOUS scope is the static value.

Thread because a ThreadLocal T is used as the backing store and so each scopes within different threads are just for that thread.

Global because it's sort of acting like a global variable!

Singleton because you access the value via a static property on the class.

Another way of thinking about this class is that it is a smuggler. It can smuggle values (including numbers of budgies) way down into call heirarchies without you needing to retrofit paramters to pass to each call. You know the way you can use class variables for temporary working purposes without them being true properties/attributes of that class (from the design rather than language persepective here)? Well, a ScopedNestableThreadGlobalSingleton T is really the same thing, but for a thread. Kinda!

Usage:

   public class SUT : NestableThreadGlobalSingleton<string>
   {
      public SUT(string value) : base(value) {}
   }

Wrap any significant "outer code" with

   using (new SUT("value"))
   {
      YOUR CODE 
   }

Then anywhere, even deep, within YOUR CODE you can get the current nested, threaded global value via

   ...
   SUT.CurrentValue()
   ...

all thread safe and properly scoped!

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on Moonrise.StandardUtils.NetStd:

Package Downloads
Moonrise.TestUtils.NetStd

Particular favourites are; PrivateWrapper - to allow access to the private methods of a "wrapped" object - via dynamic. Creator - To create repeatable but random data for "filled" classes to test - various properties available to control the range of filling. This one's the dog's!

Moonrise.Samples

Samples for how to use the Moonrise libraries. YOU MUST READ THE README!

Moonrise.Microsoft.EncryptedJsonConfiguration

Enables Moonrise.Utils.Standard.Config decryption to work transparently with the Microsoft way of doing settings. Simply .AddEncyptedJsonFile(...) to the IConfigurationBuilder. Also see the package folder for a command-line app that uses Moonrise.Utils.Standard.Config en/decryption with examples.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
5.2024.209.8452 359 2/9/2024
4.2021.105.19002 3,127 1/5/2021
4.2020.1217.19040 998 12/17/2020
4.2020.1217.12261 1,021 12/17/2020
4.2020.1217.11420 902 12/17/2020
4.2020.1217.8545 941 12/17/2020
4.2020.1213.22305 981 12/13/2020
4.2020.1211.13060 996 12/11/2020
4.2020.1211.8544 948 12/11/2020
4.2020.1207.10060 907 12/7/2020
4.2020.1206.16343 1,021 12/6/2020
4.2020.1124.20432 1,060 11/24/2020
4.2020.1120.18304 851 11/20/2020
4.2020.1120.14544 864 11/20/2020
4.2020.1119.15240 839 11/19/2020
4.2020.1118.14322 849 11/18/2020
4.2020.1118.12323 910 11/18/2020
4.2020.1116.22082 1,042 11/16/2020
4.2020.1116.16040 850 11/16/2020
4.2020.1110.19400 930 11/10/2020
3.2020.1106.15011 628 11/9/2020
3.2019.607.7582 1,096 6/7/2019
3.2019.224.21362 768 2/24/2019
3.2019.218.19031 819 2/18/2019
3.2019.213.21105 821 2/13/2019
3.2019.213.21071 777 2/13/2019
3.2019.131.13405 800 1/31/2019
3.2018.806.15135 1,033 8/6/2018
3.2018.723.10262 980 7/23/2018
3.2018.713.9112 1,361 7/13/2018

Removed any sub-dependencies on .Net Std 1.6.1. Also removed Restorable{T} as it was a gimmick class anyway!