COINNP.Client 1.0.0

dotnet add package COINNP.Client --version 1.0.0
NuGet\Install-Package COINNP.Client -Version 1.0.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="COINNP.Client" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add COINNP.Client --version 1.0.0
#r "nuget: COINNP.Client, 1.0.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 COINNP.Client as a Cake Addin
#addin nuget:?package=COINNP.Client&version=1.0.0

// Install COINNP.Client as a Cake Tool
#tool nuget:?package=COINNP.Client&version=1.0.0

COIN Number Portability Entities

This library, available on NuGet, provides a 'wrapper' for COIN's Number Portability Library. This library provides functionality to make life easier in an 'idiomatic C#' way, whereas COIN's library may have a few design choices that do not always align with best practices or latest standards. This library aims to solve that, without breaking COIN's API or asking COIN to change / break their API and/or NP library.

Among others, this library:

  • Provides an NPClient which hides a lot of complexity
  • Uses IOptions<T> for configuring the NPClient and Ilogger<T> for logging and easy integration
  • Provides interfaces like INPMessageHandler which greatly simplify handling NP messages and still offering total control and flexibility
  • Async API for sending/receiving NP messages

This library uses the COINNP.Entities. Switching from the Vereniging-COIN.Sdk.NP library to this library should be straightforward; the actual object model (concerning the NP messages) is largely the same as COIN's object model.

Quickstart

Install the NuGet package:

dotnet add package NPClient

To be able to send and receive NP messages you need an NPClient. Let's create one:

var npclient = new NPClient(
    Options.Create(
        new NPClientOptions()
        {
            ConsumerName = "API_T_EXAMPLE",
            EncryptedHmacSecretFile = "path/to/shared.key",
            PrivateKeyFile = "path/to/private.key",
            PrivateKeyFilePassword = "T0pS3Cr3t!",
            SSEUri = new Uri("https://test-api.coin.nl/number-portability/v3/dossiers/events"),
            RESTUri = new Uri("https://test-api.coin.nl/number-portability/v3/"),
            BackoffPeriod = TimeSpan.FromSeconds(10),
            NumberOfRetries = 15
        }
    ),
    new MyHandler()
);

As you can see, a handler of type MyHandler is provided. This handler needs to implement INPMessageHandler. In it's simplest form this could look like:

public class MyHandler : INPMessageHandler
{
    public Task<Acknowledgement> OnMessageAsync(MessageEnvelope messageEnvelope, CancellationToken cancellationToken = default)
    {
        // Do something with messageEnvelope here

        // Return `Ack` to acknowledge the message, false otherwise
        return Task.FromResult(Acknowledgement.ACK);
    }
    public Task OnExceptionAsync(Exception exception) => Task.CompletedTask;
    public void OnFinalDisconnect(Exception exception) { }
    public Task OnKeepAliveAsync() => Task.CompletedTask;
    public Task OnUnknownMessageAsync(string messageId, string message) => Task.CompletedTask;
}

Next, the NPClient should be started to start listening for messages. You can use any one of the three provided methods, which correspond with COIN's NumberPortabilityServiceConsumer methods:

npclient.StartConsumingAll();
// ...or
npclient.StartConsumingUnconfirmed(...);
// ...or
npclient.StartConsumingUnconfirmedWithOffsetPersistence(...);

From that point on, the OnMessageAsync method on the MyHandler will be invoked for every received NP message (after it passes any messagetype filters).

Sending a message is even simpler. For brevity the below example uses a simple Cancel message:

var cancel = new MessageEnvelope(
    new Header(
        new Sender("SNDO", "SSP"),
        new Receiver("RCVO", "RSP"),
        DateTimeOffset.Now
    ),
    new Cancel("FOO-123456789", "Hello world!")
);

await client.SendMessageAsync(cancel);

You are now ready to send, receive and handle messages.

SimpleNPMessageHandler

We provide a SimpleNPMessageHandler; a basic class that implements INPMessageHandler and does the following:

  • Messages are passed to an OnMessageDelegate
  • Other events (keepalive, unknownmessage, exception and finaldisconnect) are not handled except for being logged to an optional logger (which defaults to a NullLoger, so effectively no logger).

This simplifies implementing a messagehandler greatly:

var npclient = new NPClient(
    ... // Options left out for brevity
    new SimpleNPMessageHandler(OnMessageAsync)
);

private static Task<Acknowledgement> OnMessageAsync(MessageEnvelope messageEnvelope, CancellationToken cancellationToken = default)
{
    // Do something with messageEnvelope
}

This does, however, have it's limitations as the name suggests. One can only handle messages this way. However, the SimpleNPMessageHandler's methods are virtual which means you can pick-and-choose to implement methods by inheriting from SimpleMessageHandler:

public class MyMessageHandler : SimpleNPMessageHandler
{
    public MyMessageHandler()
        : base(OnMessageAsyncImpl) { }

    private static Task<Acknowledgement> OnMessageAsyncImpl(MessageEnvelope messageEnvelope, CancellationToken cancellationToken = default)
    {
        // Do something with messageEnvelope here...
        return Task.FromResult(Acknowledgement.ACK);
    }

    public override Task OnExceptionAsync(Exception exception)
    {
        // Do something with exception here...
        return Task.CompletedTask;
    }

    public override Task OnUnknownMessageAsync(string messageId, string message)
    {
        // Do something with message / messageId here...
        return Task.CompletedTask;
    }
}

Using the SimpleNPMessageHandler is discouraged, implementing an INPMessageHandler is encouraged. The SimpleMessageHandler is provided mostly for convenience purposes where only a simple delegate (OnMessageDelegate) is needed to get quick results.

IOptions<> and Dependency Injection

We provide NPClientOptions which can be passed to the NPClient constructor which will convert it internally to an NPClientConfiguration which will in turn be used by the NPClient for it's configuration. This means it's easy to configure the NPClient:

// Read configuration file and create a configurtion provider
var configprovider = new ConfigurationBuilder()
    .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
    .AddJsonFile("appsettings.json")
    .Build();

// Set up a DI provider
var serviceprovider = new ServiceCollection()
    .Configure<NPClientOptions>(configprovider.GetRequiredSection("NPClient"))
    .AddSingleton<INPMessageHandler, MyMessageHandler>()  // Register messagehandler
    .AddSingleton<INPClient, NPClient>()                // Register NPClient
    .BuildServiceProvider();

// Create NPClient
var npclient = serviceprovider.GetRequiredService<INPClient>();

And in appsettings.json:

{
  "NPClient": {
    "ConsumerName": "API_T_EXAMPLE",
    "EncryptedHMacSecretFile": "path/to/shared.key",
    "PrivateKeyFile": "path/to/private.key",
    "PrivateKeyFilePassword": "T0pS3Cr3t",
    "SSEUri": "https://test-api.coin.nl/number-portability/v3/dossiers/events",
    "RESTUri": "https://test-api.coin.nl/number-portability/v3/",
    "BackoffPeriod": "0:00:01",
    "NumberOfRetries": 15
  }
}

NPClientOptions vs NPClientConfiguration

If you want more control over the NPClient's configuration (for example when the keys are not stored in files but elsewhere) you can initialize an NPClientConfiguration:

var config = new NPClientConfiguration(...);

This class offers a static FromNPClientOptions() convenience method that takes NPClientOptions but also provides convenience methods to read the required RSA and HMACSHA256 from files. If these are stored elsehwere you can simply provide an RSA and HMACSHA256 to the NPClientConfiguration's constructor.

IValueHelper and ValueHelper

When converting messages from- and to COIN NP messages some conversion is done. Values like Y and N are converted into actual booleans or the value 3 is converted into VAT.High for a VAT property etc. etc. and vice versa. During this process an IValueHelper is used. This interface provides methods that can affect the conversion.

We provide a ValueHelper class which exposes a Default instance with default values. An instance of a ValueHelper can be instantiated providing a ValueHelperOptions object. This class controls the ValueHelper and can be used to change the handling of "COIN values" to- and from this library's messages. For example, you could change the default date format (which is yyyyMMddHHmmss) to any format you like. However, be aware that changing these values may result in the COIN NP message being incompatible with COIN's NP process! We recommend implementing an IValueHelper only when the default ValueHelper doesn't provide the required conversion(s).

An IValueHelper can be provided to an NPClient's constructor which will then use the provided IValueHelper internally when converting to- (sending) and from (receiving) COIN NP messages.

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 netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  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

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.0.0 340 2/21/2024