wan24-Core 1.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package wan24-Core --version 1.1.0                
NuGet\Install-Package wan24-Core -Version 1.1.0                
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="wan24-Core" Version="1.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add wan24-Core --version 1.1.0                
#r "nuget: wan24-Core, 1.1.0"                
#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 wan24-Core as a Cake Addin
#addin nuget:?package=wan24-Core&version=1.1.0

// Install wan24-Core as a Cake Tool
#tool nuget:?package=wan24-Core&version=1.1.0                

wan24-Core

This core library contains some .NET extensions:

  • Disposable base class for disposable types, which supports asynchronous disposing
    • Dispose attribute for fields/properties which should be disposed automatic when disposing
    • Worker
  • Type helpr (type loading)
  • Secure byte array, which clears its contents when disposing
  • Pool rented array as disposable object
  • Byte array extensions
    • Endian conversion
    • Bit-converter (endian-safe)
  • Array helper extensions
    • Offset/length validation
  • Enumerable extensions
    • Combine enumerables
    • Chunk enumerables
  • Reflection extensions
    • Automatic parameter extension when invoking a method (with DI support)
    • Synchronous/asynchronous method invokation
    • Automatic constructor invokation using a given parameter set (with DI support)
    • Nullability detection
  • Delegate extensions
    • Delegate list invokation (with or without return values, with DI support)
    • Asynchronous delegate list invokation (with or without return values, with DI support)
  • Task extensions
    • Result getting of a generic task
    • Asynchronous task list awaiting
    • Shortcuts for await configurations
  • DI helper
    • Service provider adoption
    • DI object factory delegates
    • Asynchronous DI object factory delegates
  • Enumeration extensions
    • Get enumeration value display string from DisplayTextAttribute or using ToString (fallback)
    • Remove flags of a mixed enumeration value
    • Get only flags of a mixed enumeration value
  • Number extensions
    • Determine if a type is a number
    • Determine if a number type is unsigned
    • Bit-converter (endian-safe)
  • JSON helper
    • Exchangeable JSON encoder/decoder delegates (using System.Text.Json per default)
  • Threading helper
    • State is a thread-safe boolean state which supports events
    • Worker is an abstract background worker, which only requires a work wait logic (event driven per default) and a worker method (synchronous or asynchronous)

How to get it

This library is available as (NuGet package "wan24-Core")[https://www.nuget.org/packages/wan24-Core/].

Type helper

You'll have to register searchable assemblies using the TypeHelper.AddAssemblies method. If you use the TypeHelper.AddTypes method, the unknown assemblies of the added types will be added as searchable assemblies automatic.

You may attach to the TypeHelper.OnLoadType event for handling requests more dynamic.

The TypeHelper.GetType method will try Type.GetType first and fall back to the helper, if no type was found.

DI helper

In order to make DI (dependency injection) working, you need to

  • set a DiHelper.ServiceProvider and/or
  • add DiHelper.(Async)ObjectFactories

The DiHelper.GetDiObjectAsync method will try to resolve the request synchronous, first. But the DiHelper.GetDiObject won't try asynchronous object factories.

Mixed enumeration value

A mixed enumeration contains X bits enumeration values, and Y bits flags:

public enum MixedEnum : int
{
    None = 0,
    Value1 = 1,
    Value2 = 2,
    Value3 = 3,
    ...
    Flag1 = 1 << 8,
    Flag2 = 1 << 9,
    FLAGS = Flag1 | Flag2 // Required to identify flags
}

The FLAGS value helps these extension methods to handle flag values:

MixedEnum value = MixedEnum.Value1 | MixedEnum.Flag1,
    valueOnly = value.RemoveFlags(),// == MixedEnum.Value1
    flagsOnly = value.OnlyFlags();// == MixedEnum.Flag1

Unsafe code

The library uses unsafe code. If you don't want/need that, you can compile the library with the NO_UNSAFE compiler constant to disable any unsafe operation. Remember to unset the unsafe compiler option, too!

Disposable base class

The DisposableBase implements the IDisposable and IAsyncDisposable interfaces. It provides some helpers and events, and also the DisposeAttribute, which can be applied to fields and properties which you wish to dispose automatic when disposing.

When your type derives from the DisposableBase, you'll need to implement the abstract Dispose method:

protected override Dispose(bool disposing)
{
    // Your dispose logic here
}

There are measures to avoid that this method is being called twice.

To implement custom asynchronous disposing:

protected override async Task DisposeCore()
{
    // Your dispose logic here
}

In order to make the DisposeAttribute working, you have to call the protected method DisposeAttributes or DisposeAttributesAsync.

The IsDisposing property value will be true as soon as the disposing process started, and it will never become false again. The IsDisposed property value will be true as soon as the disposing process did finish.

Worker

The Worker base class allows implementing a background worker with your own work waiting logic (timer or event driven f.e.) and synchronous or asynchronous worker methods.

The base class handles the start/stop and exception handling logic, and it provides events to listeners.

public class MyWorker : Worker
{
    // Manage a queue with work
    protected readonly Queue<Stream> MyWork = new();

    // Reset the work state, 'cause we're going to use it as event, 
    // which will be set as soon as work is available
    public MyWorker() : base() => Work.IsSet = false;

    // Add work to the queue and update the work state
    public void AddWork(Stream stream)
    {
        EnsureUndisposed();
        lock(SyncObject)
        {
            MyWork.Enqueue(stream);
            Work.IsSet = true;
        }
    }

    // We want to work asynchronous on streams
    protected override async Task DoWorkAsync()
    {
        // Process the queue unless cancelled, or the queue is empty
        while(!IsCancelled && !IsDisposing && Work.IsSet)
        {
            // Dequeue the next stream and reset the work state, if the queue is empty
            Stream stream;
            lock(SyncObject)
            {
                stream = MyWork.Dequeue();
                if(MyWork.Count < 1) Work.IsSet = false;
            }
            // Process the stream
            try
            {
                ...
            }
            finally
            {
                await stream.DisposeAsync();
            }
        }
    }

    // Dispose queued streams
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        MyWork.DisposeAll();
    }

    // Dispose queued streams asynchronous
    protected override async Task DisposeCore()
    {
        await base.DisposeCore();
        await MyWork.DisposeAllAsync();
    }
}

The default work wait logic does run the worker as soon as the work state is set, so we don't need to implement our own work wait logic, since we're using the work state after we've enqueued new work.

We implement an asynchronous worker method, 'cause we're going to process streams. In this method we dequeue and process streams unless the queue is empty, or the worker was cancelled. We have to reset the work state as soon as we took the last enqueued stream out of the queue.

Because the queue we use isn't thread-safe, we use the SyncObject for thread synchronization.

Finally we ensure queued, but never processed streams are disposed, if the worker is disposing. For this we override the synchronous and asynchronous disposing logic to append our own disposing.

Another example using a timer:

public class MyWorker : Worker
{
    // The timer we want to use
    protected readonly System.Timers.Timer Timer;

    public MyWorker()
    {
        // We reset the work state, because we want to use it 
        // as work event when the timer elapsed
        Work.IsSet = false;
        // If the timer was elapsed, the worker method should run
        Timer = new()
        {
            AutoReset = false
        };
        Timer.Elapsed = (s, e) => Work.IsSet = true;
        // Worker start/stop needs to start/stop the timer
        Running.OnSetLocked += (s, e) => Timer.Start();
        Running.OnResetLocked += (s, e) => Timer.Stop();
    }

    // Our worker implementation
    protected override void DoWork()
    {
        bool restartTimer = true;
        try
        {
            // Work goes here
        }
        catch
        {
            // Avoid restarting the timer in case of any error
            restartTimer = false;
            throw;
        }
        finally
        {
            // Start the timer again, if the worker wasn't cancelled
            if(restartTimer && !IsCancelled && !IsDisposing) Timer.Start();
        }
    }

    // Ensure our timer is going to be disposed, too
    protected override void Dispose(bool disposing)
    {
        Timer.Stop();
        base.Dispose(disposing);
        Timer.Dispose();
    }
}

The default work wait logic uses the work state as work event, which needs to be set to execute the worker method(s). If you need to implement an own logic, you can override the WaitWorkLogic or WaitWorkLogicAsync methods, which should return in case the worker is stopping, or work is available. Then you don't have to use the work state at all.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

NuGet packages (14)

Showing the top 5 NuGet packages that depend on wan24-Core:

Package Downloads
Stream-Serializer-Extensions

Serializer extensions for .NET Stream objects.

wan24-Compression

Compression helper

wan24-Crypto

Crypto helper

wan24-Crypto-BC

Bouncy Castle adoption to wan24-Crypto

wan24-Compression-LZ4

LZ4 adoption for wan24-Compression

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.45.0 79 11/16/2024
2.44.0 98 11/10/2024
2.43.0 89 11/3/2024
2.42.0 381 10/27/2024
2.41.0 79 10/21/2024
2.40.0 87 10/20/2024
2.39.0 97 9/29/2024
2.38.0 623 9/21/2024
2.37.0 114 9/15/2024
2.36.0 289 9/8/2024
2.35.0 227 8/24/2024
2.34.0 639 8/16/2024
2.33.0 230 8/4/2024
2.32.0 416 7/13/2024
2.31.0 391 7/6/2024
2.30.0 182 6/29/2024
2.29.0 349 6/22/2024
2.28.0 324 6/15/2024
2.27.0 97 6/8/2024
2.26.0 120 6/1/2024
2.25.0 127 5/26/2024
2.24.0 133 5/20/2024
2.23.0 172 5/11/2024
2.22.0 335 5/9/2024
2.21.0 139 5/5/2024
2.20.0 161 4/28/2024
2.19.0 157 4/20/2024
2.18.1 158 4/14/2024
2.18.0 344 4/12/2024
2.17.0 123 4/7/2024
2.16.0 215 3/30/2024
2.15.1 121 3/30/2024
2.15.0 112 3/30/2024
2.14.0 138 3/24/2024
2.13.0 148 3/17/2024
2.12.0 189 3/15/2024
2.11.0 153 3/10/2024
2.10.1 127 3/10/2024
2.10.0 229 3/9/2024
2.9.2 298 3/2/2024
2.9.1 132 3/2/2024
2.9.0 165 3/2/2024
2.8.0 138 2/25/2024
2.7.1 127 2/25/2024
2.7.0 113 2/25/2024
2.6.0 274 2/24/2024
2.5.0 117 2/20/2024
2.4.0 124 2/18/2024
2.3.2 186 2/17/2024
2.3.1 123 2/17/2024
2.3.0 121 2/17/2024
2.2.0 399 1/20/2024
2.1.0 125 12/23/2023
2.0.0 200 12/17/2023
1.43.0 161 11/27/2023
1.42.0 295 11/11/2023
1.41.2 119 11/4/2023
1.41.1 118 11/4/2023
1.41.0 118 11/4/2023
1.40.0 264 10/29/2023
1.39.0 276 10/21/2023
1.38.2 147 10/15/2023
1.38.1 319 10/14/2023
1.38.0 136 10/14/2023
1.37.0 138 10/13/2023
1.36.0 324 10/7/2023
1.35.0 212 10/1/2023
1.34.0 201 9/27/2023
1.33.0 124 9/20/2023
1.32.1 309 9/19/2023
1.32.0 114 9/19/2023
1.31.1 170 9/16/2023
1.31.0 185 9/16/2023
1.30.1 271 9/10/2023
1.30.0 136 9/10/2023
1.29.0 320 9/3/2023
1.28.0 141 8/26/2023
1.27.0 143 8/19/2023
1.26.0 163 8/5/2023
1.25.1 273 7/30/2023
1.25.0 263 7/30/2023
1.24.0 387 7/22/2023
1.23.0 136 7/9/2023
1.22.0 141 6/25/2023
1.21.0 162 6/24/2023
1.20.0 159 6/17/2023
1.19.0 204 6/11/2023
1.18.2 157 6/10/2023
1.18.1 157 6/9/2023
1.18.0 346 6/8/2023
1.17.0 144 6/4/2023
1.16.0 488 6/3/2023
1.15.0 317 5/29/2023
1.14.0 150 5/29/2023
1.13.0 152 5/28/2023
1.12.0 323 5/27/2023
1.11.0 143 5/24/2023
1.10.0 144 5/23/2023
1.9.0 133 5/22/2023
1.8.2 316 5/20/2023
1.8.1 156 5/20/2023
1.8.0 150 5/20/2023
1.7.1 171 5/13/2023
1.7.0 206 5/11/2023
1.6.1 1,519 4/26/2023
1.6.0 390 4/25/2023
1.5.0 420 4/22/2023
1.4.0 165 4/22/2023
1.3.0 303 4/16/2023
1.2.0 248 4/10/2023
1.1.0 188 4/7/2023
1.0.1 203 4/1/2023