KinsonDigital.Carbonate 1.0.0-preview.18

The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org. Prefix Reserved
This is a prerelease version of KinsonDigital.Carbonate.
dotnet add package KinsonDigital.Carbonate --version 1.0.0-preview.18
NuGet\Install-Package KinsonDigital.Carbonate -Version 1.0.0-preview.18
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="KinsonDigital.Carbonate" Version="1.0.0-preview.18" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add KinsonDigital.Carbonate --version 1.0.0-preview.18
#r "nuget: KinsonDigital.Carbonate, 1.0.0-preview.18"
#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 KinsonDigital.Carbonate as a Cake Addin
#addin nuget:?package=KinsonDigital.Carbonate&version=1.0.0-preview.18&prerelease

// Install KinsonDigital.Carbonate as a Cake Tool
#tool nuget:?package=KinsonDigital.Carbonate&version=1.0.0-preview.18&prerelease

logo

Carbonate

Build PR Status Check Test PR Status Check Technical Debt Maintainability Rating Vulnerabilities Bugs Code Smells Duplicated Lines (%) Code Coverage Latest NuGet Release Nuget Downloads Good First Issues Discord

!! NOTICE !!

This library is still under development and is not at v1.0.0 yet!! However, all of the major features are available, so we encourage you to use the library and provide feedback. That is what open source is all about. 🥳

📖 About Carbonate 📖

Carbonate is a messaging library built on the observable pattern, empowering seamless and dependable push-and-pull message handling across various parts or systems within an application. This fosters decoupling among different components, enhancing your application's overall testability as well as separating cross-cutting concerns. You can choose if you want to send out a push notification with or without data or if you want to poll for a notification with or without data. These result in data only flowing in one direction. You can also choose to push data out and receive data back in a single notification. For a real-world example, check out the Velaptor code base which is an open-source 2D game development framework. This library has been vital for decoupling the different sub-systems and increasing its testability. Go here for information on the observable pattern. This design pattern has been extensively covered in various tutorials and examples across the web, making it well-documented, widely recognized, and a highly popular programming pattern.

[!Note] Click here to view all of the sample projects.

✨ Features & Benefits ✨

Features:

  • Send push notifications with no data
  • Send push notifications with data only going out
  • Send push notifications with data only being returned
  • Send push notifications with data going out and and being returned
  • Interfaces and abstractions are provided for custom implementations and to provide testability Benefits:
  • Increases decoupling
  • Increases testability
  • Works well with dependency injection
  • Sends data and events without needing to change the public API of your library/project
  • Promotes the Open/Closed Principle

💡 Examples 💡

Below are some examples to demonstrate some basic uses of Carbonate. This library is very flexible but how you use it depends on the needs of your application.

Non-directional push notifications

To send a non-directional push notification, you can use the PushReactable class. You subscribe using the Subscribe() method by sending in the subscription object. The term non-directional means that no data is being sent out or returned from the notification call stack. This is great for sending a notification that an event has occurred when no data is needed. Every notification sent out contains a unique ID, which subscribers must use to receive the intended notification, ensuring its exclusivity and eliminating the need for additional logic to filter out each notification going out. <details closed><summary>Subscription Example</summary>

var messenger = new PushReactable(); // Create the messenger object to push notifications
var subId = Guid.NewGuid(); // This is the ID used to identify the event
// Subscribe to the event to receive messages
var subscription = new ReceiveSubscription(
id: subId,
onReceive: () => Console.WriteLine("Received a message!"),
name: "my-subscription",
onUnsubscribe: () => Console.WriteLine("Unsubscribed from notifications!"),
onError: (ex) => Console.WriteLine($"Error: {ex.Message}")
);
IDisposable unsubscriber = messenger.Subscribe(subscription);
messenger.Push(subId); // Will invoke all onReceive 'Actions' subscribed to this reactable
unsubscriber.Dispose(); // Will only unsubscribe from this subscription

</details> <details closed><summary>How To Unsubscribe Example</summary>

var mySubscription = new ReceiveSubscription(
id: subId,
name: "my-subscription",
onReceive: () => { Console.WriteLine("Received notification!"); }
onUnsubscribe: () =>
{
unsubscriber.Dispose(); // Will unsubscribe from further notifications
});

</details> <details closed><summary>How Not To Unsubscribe Example</summary> Below is an example of what you SHOULD NOT do.

IDisposable? unsubscriber;
var subId = Guid.NewGuid(); // This is the ID used to identify the event
var badSubscription = new ReceiveSubscription(
id: subId,
name: "bad-subscription",
onReceive: () =>
{
// DO NOT DO THIS!!
unsubscriber.Dispose(); // An exception will be thrown in here
});
var messenger = new PushReactable();
unsubscriber = messenger.Subscribe(badSubscription);
messenger.Push(subId);

</details>

[!Tip] If you want to receive a single notification, unsubscribe from further notifications by calling the Dispose() method on the IDisposable object returned by the Reactable object. All reactable objects return an unsubscriber object for unsubscribing at a later time. The unsubscriber is returned when invoking the Subscribe() method. Unsubscribing can be done anytime except in the notification delegates onReceive, onRespond, and onReceiveRespond. [!Tip] If an attempt is made to unsubscribe from notifications inside of any of the notification delegates, a NotificationException will be thrown. This is an intentional design to prevent the removal of any internal subscriptions during the notification process. Of course, you can add a try...catch in the notification delegate to swallow the exception, but again this is not recommended.

One way push notifications

To facilitate one way data transfer through push notifications, you can employ the PushReactable<TIn> or PullReactable<TOut> types while subscribers utilize the ReceiveSubscription<TIn> or RespondSubscription<TOut> types for their subscriptions. Setting up and using this approach follows the same steps as in the previous example. In this context, the term one-directional signifies that data exclusively flows in one direction either out from the source to the subscription delegate or from the subscription delegate to the source. <details closed><summary>One Way Out Notification Example</summary>

var messenger = new PushReactable<string>(); // Create the messenger object to push notifications with data
var subId = Guid.NewGuid(); // This is the ID used to identify the event
// Subscribe to the event to receive messages
IDisposable unsubscriber = messenger.Subscribe(new ReceiveSubscription<string>(
id: subId,
onReceive: (msg) => Console.WriteLine(msg),
name: "my-subscription",
onUnsubscribe: () => Console.WriteLine("Unsubscribed from notifications!"),
onError: (ex) => Console.WriteLine($"Error: {ex.Message}")
));
messenger.Push("hello from source!", subId); // Will invoke all onReceive 'Actions' that have subscribed with 'subId'.
messenger.Unsubscribe(subId); // Will invoke all onUnsubscribe 'Actions' that have subscribed with 'subId'.

</details> <details closed><summary>One Way In Notification(Polling) Example</summary>

var messenger = new PullReactable<string>(); // Create the messenger object to push notifications to receive data
var subId = Guid.NewGuid(); // This is the ID used to identify the event
// Subscribe to the event to receive messages
IDisposable unsubscriber = messenger.Subscribe(new RespondSubscription<string>(
id: subId,
onRespond: (msg) => "hello from subscriber!",
name: "my-subscription",
onUnsubscribe: () => Console.WriteLine("Unsubscribed from notifications!"),
onError: (ex) => Console.WriteLine($"Error: {ex.Message}")
));
var response = messenger.Pull(subId); // Will invoke all onRespond 'Actions' that have subscribed with 'subId'.
Console.WriteLine(response);
messenger.Unsubscribe(subId); // Will invoke all onUnsubscribe 'Actions' that have subscribed with 'subId'.

</details>

Two Way Push Pull Notifications

To enable two way push notifications, allowing data to be sent out and returned, you can employ the PushPullReactable<TIn, TOut> type. Subscribers, on the other hand, utilize the ReceiveRespondSubscription<TIn, TOut> when subscribing. This approach proves useful when you need to send a push notification with data required by the receiver, who then responds with data back to the source that initiated the notification. This is synonymous with sending an email out to a person and getting a response back. <details closed><summary>Two Way Notification Example</summary>

var favoriteMessenger = new PushPullReactable<string, string>();
var subId = Guid.NewGuid(); // This is the ID used to identify the event
var unsubscriber = favoriteMessenger.Subscribe(new ReceiveRespondSubscription<string, string>(
id: subId,
onRespond: (data) => data switch
{
"prog-lang" => "C#",
"food" => "scotch eggs",
"past-time" => "game development",
"music" => "hard rock/metal",
},
name: "favorites",
onUnsubscribe: () => Console.WriteLine("Unsubscribed from notifications!"),
onError: (ex) => Console.WriteLine($"Error: {ex.Message}")
));
Console.WriteLine($"Favorite Language: {favoriteMessenger.PushPull("prog-lang", subId)}");
Console.WriteLine($"Favorite Food: {favoriteMessenger.PushPull("food", subId)}");
Console.WriteLine($"Favorite Past Time: {favoriteMessenger.PushPull("past-time", subId)}");
Console.WriteLine($"Favorite Music: {favoriteMessenger.PushPull("music", subId)}");

</details>

[!Note] The difference between one way and two way notifications is that one way notifications enable data travel in one direction whereas two way notifications enable data travel in both directions. The terms 'Push', 'Pull', 'Receive', and 'Respond' should give a clue as to the direction of travel of the data. [!Tip] Most of the time, the built in reactable implementations will suit your needs. However, if you have any requirements that these can't provide, you can always create your own custom implementations using the interfaces provided.

🙏🏼 Contributing 🙏🏼

Interested in contributing? If so, click here to learn how to contribute your time or here if you are interested in contributing your funds via a one-time or recurring donation.

🔧 Maintainers 🔧

x-logo-light-mode Calvin Wilkinson (KinsonDigital GitHub Organization - Owner)

🚔 Licensing and Governance 🚔

Contributor Covenant GitHub This software is distributed under the very permissive MIT license and all dependencies are distributed under MIT-compatible licenses. This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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.
  • net8.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on KinsonDigital.Carbonate:

Package Downloads
KinsonDigital.CASL The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org.

CASL is a simplistic cross-platform, .NET library for playing and managing audio powered by OpenAL 1.1 using software rendering.

KinsonDigital.Velaptor The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org.

2D game or application development framework that provides 2D rendering, audio, keyboard and mouse input, etc.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0-preview.18 754 4/4/2024
1.0.0-preview.17 191 1/23/2024
1.0.0-preview.16 2,527 9/14/2023
1.0.0-preview.15 487 7/31/2023
1.0.0-preview.14 1,075 1/25/2023
1.0.0-preview.13 102 1/18/2023
1.0.0-preview.12 119 1/10/2023
1.0.0-preview.11 113 1/5/2023
1.0.0-preview.10 105 1/5/2023
1.0.0-preview.9 93 1/4/2023
1.0.0-preview.8 110 12/28/2022
1.0.0-preview.7 121 12/26/2022
1.0.0-preview.6 90 12/23/2022
1.0.0-preview.5 102 12/22/2022
1.0.0-preview.4 98 12/21/2022
1.0.0-preview.3 83 12/21/2022
1.0.0-preview.2 82 12/21/2022
1.0.0-preview.1 93 12/14/2022