ZeroFrictionLogger 1.1.1

dotnet add package ZeroFrictionLogger --version 1.1.1
                    
NuGet\Install-Package ZeroFrictionLogger -Version 1.1.1
                    
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="ZeroFrictionLogger" Version="1.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ZeroFrictionLogger" Version="1.1.1" />
                    
Directory.Packages.props
<PackageReference Include="ZeroFrictionLogger" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ZeroFrictionLogger --version 1.1.1
                    
#r "nuget: ZeroFrictionLogger, 1.1.1"
                    
#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.
#:package ZeroFrictionLogger@1.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ZeroFrictionLogger&version=1.1.1
                    
Install as a Cake Addin
#tool nuget:?package=ZeroFrictionLogger&version=1.1.1
                    
Install as a Cake Tool

ZeroFrictionLogger

TL;DR Zero config, zero dependency exception handler and logger, logs designed for both human reading and automated processing.

Features thread-safe logging, fallback to console and speedblink testing. logger source code builds and runs on .NET Core 2.1 and 8.0 LTS; have seen it build and run on Linux with .NET Core 8.0 LTS. Writes to log without caching. Prebuilt DLL on NuGet targets netstandard2.1; Logger test project source code, including the logger core, is available on GitHub. See the Quick Start section for... a quick start 😃

187 lines of executable code, 500+ due to whitespace and comments (MIT-license and for intellisense XML) covered by 115 dual purpose unit tests, providing proof of work and low-level living documentation.

See screenshots of passing unit tests, coverage and latest documentation updates on GitHub README.

Quick Start

Using directive

using System.Reflection;
using Err = ZeroFrictionLogger.Log;

Initialise

Err.InitialiseErrorHandling(Assembly.GetExecutingAssembly().GetName().Name);

Handle exception

catch (Exception ex)
{
    Err.HandleException(MethodBase.GetCurrentMethod().Name, ex.Message, ex.StackTrace);
}

...without stack trace

catch (Exception ex)
{
    Err.HandleExceptionWithoutStackTrace(MethodBase.GetCurrentMethod().Name, ex.Message);
}

Logging

Err.LogDebug("Penicillin discovered by accident");
Err.LogInfo("Rain in Ireland identified as liquid sunshine");
Err.LogWarning("Animal print pants outta control");
Err.LogAudit("Calling external process xyz");
Err.LogError("Pizza with pineapple detected");
Err.LogFatal("It was at that moment Nathan knew...");

Opt in/out of default behaviour, full list

You may want to customize logger behaviour. Here is how:

Opt in/out of Marker file Notes
retaining v1.0.0 more human readable timestamps retain-non-ISO-8601-utc-timestamp.txt Checked once by InitialiseErrorHandling()
log level TRACE use-trace.txt Checked once by InitialiseErrorHandling()
log level DEBUG no-debug.txt Checked once by InitialiseErrorHandling()
log level INFO no-info.txt Checked once by InitialiseErrorHandling()
log level WARN no-warn.txt Checked once by InitialiseErrorHandling()
log level ERROR not possible Always logged
log level FATAL not possible Always logged
log level AUDIT not possible Always logged
speedblink text no-speedblink.txt Checked once by InitialiseErrorHandling()
using UTC time no-utc.txt Checked once by InitialiseErrorHandling(), alternative is local time
use milliseconds use-millisec.txt Checked once by InitialiseErrorHandling()

InitialiseErrorHandling() checks marker file presence in the host app runtime folder. The log starts with a status update on customized behaviour and briefly informs you on how to opt-out.

Creating reports from grepable markers - Out of scope but not out of heart

While out of scope for the logger, extracting an audit (or any) report from logfile based on a grepable marker (here #audit) can be a real time saver - allowing you to create reports before they are built.

The one-liner below works from Windows CMD. Tested, works.

findstr /C:#audit app.log > audit.txt

Copied this one-liner from my Linux VM. It works.

grep "#audit" Test.log > audit.txt

Log file retention - Out of scope but not out of heart

My TAF host app handles log file retention programmatically, making a copy to report folder where it can also be accessed from the HTML report. While retention is out of scope for the logger itself for the sake of simplicity, you can still archive logs with a timestamp in a straighforward way. Below you find a Windows CMD batchfile example adding a YYYY-MM-DD_HH_MM_SSmm prefix to app.log.

It does pad hours before 10:00 to prevent filename issues. Does not require PowerShell.

Tested it, app.log was copied to 2025-08-14_09_09_1228-app.log OK.

set dd=%DATE:~7,2%
set mm=%DATE:~4,2%
set yyyy=%DATE:~-4%
set hh=%time:~0,2%
set hh=%hh: =0%
set min=%time:~3,2%
set ss=%time:~6,2%
set ms=%time:~9,2%

set timestamp=%yyyy%-%mm%-%dd%_%hh%_%min%_%ss%%ms%

REM echo timestamp = %timestamp%

copy app.log %timestamp%-app.log

and now the same on Linux:

cp app.log "$(date +%Y-%m-%d_%H_%M_%S%2N)-app.log"

Confirmed to work before 10:00. Copied a log file to 2025-12-03_09_51_4502-app.log OK

NuGet package

Nuget package targetting .netstandard2.1 is available on NuGet. To use the logger in older environments, build from source (see below)

TestZeroFriction Source and Unit Test (Living Documentation)

The xUnit test project TestZeroFrictionLogger.sln is available on GitHub:

Logger core:

Test Suite:

  • TestCases.cs (115-ish xUnit unit tests)
  • TestSupport.cs (log content check)
  • AssemblyInfo.cs (enforce sequential xUnit test execution)

Test Project Config:

  • TestZeroFrictionLogger.sln
  • Test.csproj (.NET Core project file)

Note: The test project uses xUnit for testing. Make sure you have it installed to build and run the tests. The test project uses .NET 8.0 and the latest xUnit packages. While the logger core supports .NET 6.0 (and earlier), the test project will not build on .NET 6.0.

Currently, the xUnit test project - using the latest components - builds and runs on .NET Core 8.0.

Unit tests pass on both Windows and Linux (Ubuntu LTS) All unit tests were confirmed passing before sharing the test project on GitHub.

Platform Compatibility Matrix

ZeroFrictionLogger Windows Linux (LTS) Mac OS
Builds on .NET Core 8.0 ✅ OK ✅ OK ⏳ Not confirmed
Runs on .NET Core 8.0 (demo app) ✅ OK ✅ OK ⏳ Not confirmed
xUnit unit tests passing with .NET Core 8.0 ✅ OK ✅ OK ⏳ Not confirmed
Builds on .NET Core 6.0 ✅ OK ⏳ Not confirmed ⏳ Not confirmed
Runs on .NET Core 6.0 (demo app) ✅ OK ⏳ Not confirmed ⏳ Not confirmed
xUnit unit tests passing with .NET Core 6.0 ❌ Not building ❌ Not building ⏳ Not confirmed
Builds on .NET Core 2.1 (Out of Service) ✅ builds ⚠️ end-of-life ⚠️ end-of-life ⚠️ end-of-life
Runs on .NET Core 2.1 (Out of Service) (demo) ✅ runs ⚠️ end-of-life ⚠️ end-of-life ⚠️ end-of-life

⚠️ .NET Core 2.1 is out of support.

Build from Source

  1. Download log.csandPascalToSentence.cs from GitHub.
  2. In Solution Explorer:
  • Right-click on your Project
  • Select Add → Existing item...
  1. Select the two downloaded .cs files and click Add

Context

Originally a by-product of a Test Automation Framework running on tool servers, VMs or bare metal, built to support teams testing mission-critical Systems Under Test running on Dev, Test, Acceptance - and, on one rare occasion, Live environments.

Why

No filtering, no surprises

Way back I had to use a mandatory logger. The logger refused to log stack traces with curly braces. I wanted simple not clever. No surprises.

No additional vulnerability

Way back the test tool I was working on started crashing intermittently at midnight. The mandatory logger included a midnight roll over feature for log file retention. The documentation was elaborate. Looked for but did not find info on how to opt out of the midnight roll over feature. The need was for simple not clever. No additional vulnerability.

No caching, no loss of data

A while ago the test tool I was using started crashing at 22:00. The tooling failed where it had never failed before, performing trivial tasks during startup which had worked thousands of times for many years. The consistent timing (22:00 plus a few sec) provided a clue the tool might be killed by an external process. Windows Event Viewer confirmed the suspicion. After reaching out to security it turned out they had introduced a new audit tool capable of killing "suspicious" processes. We solved the issue with a slightly changed regression test start time and adding the tool to an allow list. No caching meant no loss of data. The time stamp of the last successfully written log line provided a clue for root cause analysis.

Simplicity as security feature

Built the original version of the logger way before november 2021. Simplicity means no surprise behaviour through runtime injection.

App logging only - no OS-level monitoring

The logger records only application events - not system logs, third party logs or framework-level logs.

Still, this does not mean you have to be blind to environmental issues. Years ago, I asked the infra team next door—already running an enterprise-grade monitoring suite—for disk and memory checks on a tool server. They said it required budget approval, which never came. Later on I built my own checks, logged the results, and included them in the reports.

Grepable markers, MVP reports

The exception methods (and logAudit) add visual markers, grepable sentinel tags (#exception, #audit) to the log. This allows to extract and share for instance audit reports without/before building them in the host app. Used the approach in a test tool with #summary, #details, #metrics, #S2R (steps to reproduce) enabling provision of reports before having built them. This allowed for initial focus on 1. tool stability and 2. testware validation - a huge time saver. The approach allowed building fancy HTML reports with pie charts and styling later, with the reduced pressure of "nice to have" rather than high-pressure "must have" features, allowing for some much-needed breathing space.

Come to think of it, you don't even need ZeroFrictionLogger to pull this off. You can probably do it already with the logger you're using right now. See Quick Start for an example.

Security - don't slam your fingers

The logger contains mechanisms to prevent leaking sensitive data to log. One of several features is HandleExceptionWithoutStackTrace, cousin of HandleException. Intended use for both is in the catch block. It is up to you as host app developer to make an informed choice to omit the stack trace from log when you suspect it might contain sensitive data.

This paragraph is like a sticker on the side of the hammer saying: Don't slam your fingers. Like a hammer the logger contains no functionality to magically auto-prevent you from slamming your fingers.

Zero config

No config is required. No XML, no JSON, no YAML. You can start developing without ever needing any of that.

Opt out levels DEBUG, INFO, WARN

As you move from Dev to Ops you may still want to opt out of log levels DEBUG, INFO and WARN.

Three Opt Out Options

  1. Comment out calls to LogDebug, LogInfo, LogWarning. Cumbersome and requires changes to code base.
  2. Grep out [DEBUG] [INFO] and [WARN] afterwards. Possible, but requires some scripting.
  3. Add marker files no-debug.txt, no-info.txt and no-warn.txt to the host app bin folder, checked by InitialiseErrorHandling.

You can still start with zero config. Can go LIVE without config. You can opt-out of log levels with minimal complexity and same code base.

The log prepared by InitialiseErrorHandling will tell you (and double check) whether levels DEBUG, INFO, WARN are active - and briefly inform on how to opt-out.

No ejection seat without parachute

Gentle reminder: there is no way to opt out of levels [ERROR], [FATAL] and [AUDIT]. That would be like providing a pilot with an ejection seat but without parachute.

While a pilot might be grateful for an ejection seat to leave a burning plane, the gratitude probably lasts longer if a parachute is included.

Tools like find, grep and fuzzy find are the fastest way to find known anomalies. Under pressure, you may end up scanning logs with your eyes nonetheless. When scrolling and speedreading, any break in monotony - like indentation, blank lines, or unusual shapes - appear like movement on screen, drawing attention. The exception handling methods include a visual marker to that end.

idea

Builds on an insight taught by James Bach, creator of the Rapid Software Testing Methodology. The idea being the human brain is hard wired to detect movement as potential danger, a survival mechanism built in over eons of evolution. A literal life hack to survive in a dangerous environment - the savannah.

When watching a fire in a fireplace, camp fire or bonfire our eyes are drawn to the movement of flames. Same for fish swimming in a fish tank or a TV screen with a sports game in a restaurant. The marker assists spotting anomalies under pressure. You can still find #exception by means of find or grep, it's just an extra hook for catching exceptions.

Opt out

  • Opt out of speedblink marker by adding no-speedblink.txt in the host app bin folder, checked by InitialiseErrorHandling
  • Alternatively grep out #speedblink afterwards, combining visual markers with improved likelyhood of pipeline compliance.

Example

2025-07-21 08:29:35 #speedblink
      ___   __  __   ___    #speedblink
     |  _|  \ \/ /  |_  |   #speedblink
     | |     \  /     | |   #speedblink
     | |_    /  \    _| |   #speedblink
     |___|  /_/\_\  |___|   #speedblink
                            #speedblink

Timezone - UTC by default, local possible

Uses Utc time with format yyyy-MM-ddTHH:mm:ssZ by default.

Opt out of Utc time in favor of local time by adding marker file no-utc.txt in host app bin folder.

Logfile retention

The app creates the log at start, replacing any previous log. Retention of logfiles is possible using scripts, batchfiles, trusted tools or by the host app making a copy. See Quick Start for an example.

log path and location

Logs are created in the host app bin folder, using the app name with .log extension.

UTF-8

UTF-8 Encoding without BOM should take care of compatibility with many other tools downstream.

Fall back to console

Failure to create or write to logfile to the host app bin folder (no write permissions?) will result in logging to console. If need be, redirection of console output to file in another folder using > or >> can provide a quick fix on both Windows and Linux.

Portability

Builds on Windows and Linux, Demo app runs on Windows and Linux. All unit tests pass on Windows and Linux. Should work on MacOS - which is a fancy way of saying it still needs to be confirmed.

Compatibility

Developing, building, running and unit testing using .NET Core 8.0 LTS. Builds and runs on Windows in a console application with .NET Core 2.1 (Out of Support)

Scaling

The logger allows a quick start at small scale. Scaling is possible with some opt out features, scripts and tools around the two core class modules. Will look into post processing for integration with the dashboard tool Grafana at a later stage.

Migration

There are many great and feature rich loggers out there, some including advanced telemetry. Will deliberately keep this logger simple not clever, lean and ...minimalistic. Being aware your host app may outgrow the possibilities of ZeroFrictionLogger, the best I can do to facilitate later migration to a feature rich enterprise logger is to provide transparent examples, unit tests and full documentation. See below.

Example log output

2025-12-03T11:40:05Z [AUDIT] start log. #audit
2025-12-03T11:40:05Z [AUDIT] Start log initialisation for app: ConsoleAppTestingLoggingNetCore2dot1OutOfSupport #audit
2025-12-03T11:40:05Z [AUDIT] trace enabled = False due to presence/absence of use-trace.txt in app path at initialisation #audit
2025-12-03T11:40:05Z [AUDIT] debug enabled = True due to presence/absence of no-debug.txt in app path at initialisation #audit
2025-12-03T11:40:05Z [AUDIT] info enabled = True due to presence/absence of no-info.txt in app path at initialisation #audit
2025-12-03T11:40:05Z [AUDIT] warn enabled = True due to presence/absence of no-warn.txt in app path at initialisation #audit
2025-12-03T11:40:05Z [AUDIT] utc enabled = True due to presence/absence of no-utc.txt in app path at initialisation #audit
2025-12-03T11:40:05Z [AUDIT] milliseconds enabled = False due to presence/absence of use-millisec.txt in app path at initialisation #audit
2025-12-03T11:40:05Z [AUDIT] retain version 1.0.0 more human readable non ISO-8601 UTC timestamp = False due to presence/absence of retain-non-ISO-8601-utc-timestamp.txt in app path at initialisation #audit
2025-12-03T11:40:05Z [AUDIT] speedblink icon enabled = True due to presence/absence of no-speedblink.txt in app path at initialisation #audit
2025-12-03T11:40:05Z [DEBUG] double check loglevel DEBUG is active
2025-12-03T11:40:05Z [INFO] double check loglevel INFO is active
2025-12-03T11:40:05Z [WARN] double check loglevel WARN is active
2025-12-03T11:40:05Z [AUDIT] Gentle reminder: levels [ERROR], [FATAL] and [AUDIT] can not be disabled. #audit
2025-12-03T11:40:05Z [AUDIT] ZFL version 1.1.1 #audit
...
2025-12-03T11:40:06Z [DEBUG] Penicillin discovered by accident.
2025-12-03T11:40:06Z [INFO] Rain in Ireland identified as liquid sunshine.
2025-12-03T11:40:06Z [WARN] Animal print pants outta control.
2025-12-03T11:40:06Z [ERROR] Pizza with pineapple detected.
2025-12-03T11:40:06Z [FATAL] It was at that moment Nathan knew...
...
2025-12-03T11:40:06Z #speedblink
      ___   __  __   ___    #speedblink
     |  _|  \ \/ /  |_  |   #speedblink
     | |     \  /     | |   #speedblink
     | |_    /  \    _| |   #speedblink
     |___|  /_/\_\  |___|   #speedblink
                            #speedblink
2025-12-03T11:40:06Z [ERROR] Cause exception for demo purpose
2025-12-03T11:40:06Z [ERROR] Attempted to divide by zero. #exception
2025-12-03T11:40:06Z [ERROR] tech info: Attempted to divide by zero. stack trace: #redacted #audit

Unit tests

All 115 unit tests are passing on Windows and Linux.

Check out the xunit unit test project for verification and living documentation through practical examples.

Full documentation

Public method documentation of log.cs.

LoggerVersion

Marker to be checked in unit tests to prove unit tests are indeed using the expected version of the DLL.

Returns: build nr of logger to be published


Zilch

Visual markers, grepable sentinel tags to catch an
uninitialized state and to prevent silent errors.

Returns: #zilch #iota #diddly-squat


IsZilch

Checks whether a value equals Zilch().

Parameters:

  • value

Returns: boolean


NotZilch

Checks whether a value is different from Zilch().

Parameters:

  • value

Returns: boolean


NullExpression

Visual markers, grepable sentinel tag to catch an
uninitialized state and to prevent silent errors.

Returns: #null-value


ReplaceNull

Returns the passed value unless it's null, in which case it returns
sentinel tag #null-value.

Parameters:

  • value

Returns: value or #null-value


ReplaceNullOrEmpty

Returns the passed value unless it's null or empty,
in which case it returns #zilch #iota #diddly-squat.

Parameters:

  • value

Returns: value or #zilch #iota #diddly-squat


RedactedExpression

Visual marker, grepable sentinel value for replacing data to be redacted.

Returns: #redacted #audit


IsRedacted

Checks whether an expression equals #redacted #audit.
Changed from private to public for unit testing.
Returns false when value is null.

Parameters:

  • value

Returns: boolean


ExplicitlyRedactAndMarkValue

Method replacing the value passed with visible, grepable markers #redacted #audit.
Value is in explicitly hiding sensitive data and providing the audit trail to prove it.

Example:

ZeroFrictionLogger.Log.LogInfo("log in using uid: " + uid +
    " and pwd: " + Err.ExplicitlyRedactAndMarkValue("password", pwd));

The method is null safe, still returns the markers as expected when value is null.
Also returns the markers as expected when context is null, replacing context with a missing context message.

Parameters:

  • context
  • value

Returns: [context] + #redacted #audit


GetLogFileExtension

Returns log file extension for use by host application for handling log file retention.

Returns: .log


GetAppName

Returns the app name passed to InitialiseErrorHandling. If the passed app name is: null, empty string or contains dotnet, xunit, testhost, zerofrictionlogger, zilch or ., then the logger defaults to "app".

Returns: host app name


GetAppPath

Returns host app path using System.AppContext.

Returns: host app path


GetLogPathAndFilename

Returns app path and app name based logfile name.

Returns: logfile path and filename


ConvertPascalCaseToSentence

Converts expression (for instance method name) in PascalCase
into a sentence (hopefully documenting the method).
Replaces a call to the Humanizer package to remain at zero dependencies.

Parameters:

  • value

Returns: sentence


LogTrace

Logs message at TRACE level. Opt-in by adding marker file:
use-trace.txt in host app path, checked during log initialisation.
Writes data instantly without caching.

Note: logger does not auto-hide sensitive data. Ensure sensitive data is handled
before calling.

Parameters:

  • msg

LogDebug

Logs message at DEBUG level. Opt-out by adding marker file:
no-debug.txt in host app path, checked during log initialisation.
Writes data instantly without caching.

Note: logger does not auto-hide sensitive data. Ensure sensitive data is handled
before calling.

Parameters:

  • msg

LogInfo

Logs message at INFO level. Opt-out by adding marker file:
no-info.txt in host app path, checked during log initialisation.
Writes data instantly without caching.

Note: logger does not auto-hide sensitive data. Ensure sensitive data is handled
before calling.

Parameters:

  • msg

LogWarning

Logs message at WARN level. Opt-out by adding marker file:
no-warn.txt in host app path, checked during log initialisation.
Writes data instantly without caching.

Note: logger does not auto-hide sensitive data. Ensure sensitive data is handled
before calling.

Parameters:

  • msg

LogError

Logs message at ERROR level.
Writes data instantly without caching.

Note: logger does not auto-hide sensitive data. Ensure sensitive data is handled
before calling.

Parameters:

  • msg

LogFatal

Logs message at AUDIT level. Also writes grepable sentinel tag #audit for
extracting an audit trail from log. Useful when making calls to external processes, URLs, or APIs
in the host application, providing a means to extract audit reports via grep tools.
Writes data instantly without caching.

Note: logger does not auto-hide sensitive data. Ensure sensitive data is handled
before calling.

Parameters:

  • msg

LogAudit

Logs message at AUDIT level. Also writes grepable sentinel tag #audit for
extracting an audit trail from log. When making calls to external processes, url's or API's in the host application this allows grepping audit trails from log. Writes data instantly without caching.

Note: logger does not auto-hide sensitive data. Ensure sensitive data is handled
before calling.

Parameters:

  • msg

IsAppNameOK

Public for unit test only. Called by InitialiseErrorHandling. Check whether the appname, passed from host app or generated by logger is appropriate. Inappropriate app names are null, empty string or containing dotnet, xunit, testhost, zerofrictionlogger, zilch or ..

Parameters:

  • appName host app name passed to InitialiseErrorHandling

HandleException

Bread-and-butter method for handling exceptions in try-catch blocks.
Logs at ERROR level and also writes a speedblink message by default.
Opt-out by including marker file: no-speedblink.txt in host app path,
checked during log initialisation. Writes data to log instantly without caching.

Note: logger does not auto-hide sensitive data. Ensure sensitive data is handled
before calling.

Parameters:

  • methodName methodname obtained through reflection: MethodBase.GetCurrentMethod().Name
  • errMsg exception message from catch block, ex.Message
  • stackTrace stack trace from catch block, ex.StackTrace

HandleExceptionWithoutStackTrace

If you as a host app dev suspect sensitive data might leak into logfile through
the exception stack trace message, use HandleExceptionWithoutStackTrace in
the try-catch block. Works similar to its cousin HandleException but replaces
the stack trace message with grepable sentinel tags #redacted #audit.

Note: logger does not auto-hide sensitive data. Ensure sensitive data is handled
before calling.

Parameters:
then

  • methodName using reflection: MethodBase.GetCurrentMethod().Name
  • errMsg exception message from catch block, ex.Message

InitialiseErrorHandling

One-stop method for starting exception handling and logging, no config needed.
Attempts to create a logfile in app folder with app name and .log extension at
each start of the app if possible. If write access is absent the fallback is
to log to console. Failure to create or write to logfile (no write permissions)
will result in an ASCII icon displayed in console with explanation.
Redirection of console output to file in another folder using > or >>
is possible on both Windows and Linux as a workaround.

Retention of logfiles can be achieved by shell scripts, batch files, or by
the host application making a copy.

In case the host appname passed to InitiliaseErrorHandling is null, an empty string or contains any of the expressions dotnet, xunit, testhost, zerofrictionlogger, zilch or . (not case sensitive) the logger will fall back to the hard coded expression "app".

parameters

  • appName appName passed explicitly from the host app using reflection or as string.

Project Policies

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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.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.
  • .NETStandard 2.1

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.1 695 12/3/2025
1.1.0 196 10/15/2025
1.0.0 162 7/29/2025
0.9.0 912 7/21/2025
0.1.6 562 7/15/2025
0.1.5 558 7/15/2025
0.1.4 561 7/14/2025
0.1.3 554 7/14/2025
0.1.2 552 7/14/2025
0.1.1 523 7/12/2025
0.1.0 510 7/11/2025