RickDotNet.Apollo 0.4.1

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

// Install RickDotNet.Apollo as a Cake Tool
#tool nuget:?package=RickDotNet.Apollo&version=0.4.1                

Apollo

Apollo aims to be a lightweight, high-performance messaging client designed to provide developers with a simple yet powerful way to incorporate flexible architectures into their .NET applications. Initially built on top of the NATS messaging system, Apollo now also supports Azure Service Bus, offering even more flexibility for your messaging needs. With Apollo, you can easily handle events, commands, and requests with minimal configuration, while benefiting from the speed and scalability of NATS and the reliability of Azure Service Bus.

RAPID DEVELOPMENT

Apollo is under rapid development. Feel free to pitch in! Join the fun at discord.gg/rick.

Vision

The goal for this library is to provide a solid foundation, of which to build upon. The library should be easy to use, and provide a simple API for developers to work with. The library should be flexible, and allow developers to swap out the underlying messaging system with minimal effort.

And that's it. Keep it simple, and keep it flexible.

Getting Started

To get started with Apollo you can run the code examples below or run the project in the demo folder. These will use the InMemoryProvider by default. In order to take full advantage of Apollo, you'll need to have a running instance of NATS or Azure Service Bus. You can find instructions on setting up NATS here and Azure Service Bus here.

Azure Service Bus Support

Apollo now supports Azure Service Bus (ASB). Note that ASB requires topics/subscriptions, so a Standard or Premium tier is necessary.

Code Example

Test Endpoint

public record TestEvent(string Message) : IEvent;

public class TestEndpoint : IListenFor<TestEvent>
{
    private static int count = 0;
    public Task HandleAsync(TestEvent message, CancellationToken cancellationToken = default)
    {
        count++; // thread safe when in syncmode
        Console.WriteLine($"Endpoint: {message}, Count: {count}");
        // simulate a delay to demonstrate concurrency
        return Task.Delay(500);
    }
}

Dependency Injection Usage

The default implementation uses an InMemoryProvider to route messages to the appropriate endpoint. A poor man's Mediator.

var endpointConfig = new EndpointConfig { ConsumerName = "endpoint", EndpointName = "Demo" };
var anonConfig = new EndpointConfig { ConsumerName = "anon", EndpointSubject = "demo.testevent" };

int count = 1; // thread-safe when in sync mode
var builder = Host.CreateApplicationBuilder();
builder.Services
    .AddApollo(
        apolloBuilder =>
        {
            apolloBuilder
                .AddEndpoint<TestEndpoint>(endpointConfig)
                .AddHandler(anonConfig, (context, token) =>
                {
                    Console.WriteLine($"Anonymous handler received: {count++}");
                    return Task.CompletedTask;
                });

            if (useNats)
            {
                apolloBuilder.AddNatsProvider(
                    opts => opts with
                    {
                        Url = "nats://localhost:4222",
                        AuthOpts = new NatsAuthOpts
                        {
                            Username = "apollo",
                            Password = "demo"
                        }
                    }
                );
            }
        }
    );

var host = builder.Build();
var hostTask = host.RunAsync();

await Task.Delay(8000);
using var scope = host.Services.CreateScope();
var serviceProvider = scope.ServiceProvider;
var apollo = serviceProvider.GetRequiredService<ApolloClient>();

var publisher = apollo.CreatePublisher(endpointConfig);

await Task.WhenAll(
    publisher.BroadcastAsync(new TestEvent("test 1"), CancellationToken.None),
    publisher.BroadcastAsync(new TestEvent("test 2"), CancellationToken.None),
    publisher.BroadcastAsync(new TestEvent("test 3"), CancellationToken.None),
    publisher.BroadcastAsync(new TestEvent("test 4"), CancellationToken.None),
    publisher.BroadcastAsync(new TestEvent("test 5"), CancellationToken.None)
);

Console.WriteLine("Press any key to exit");
Console.ReadKey();

Direct Client Usage

Alternatively, you can use the ApolloClient directly, without the need for dependency injection.

var endpointConfig = new EndpointConfig
{
    Namespace = "dev.myapp", // optional prefix for isolation
    EndpointName = "My Endpoint", // slugified if no subject is provided (my-endpoint)
    ConsumerName = "unique-to-me", // required for load balancing and durable scenarios
    IsDurable = false // marker for subscription providers
};

var endpointProvider = new EndpointProvider();
var demo = new ApolloClient(endpointProvider: endpointProvider);
var endpoint = demo.AddEndpoint<TestEndpoint>(endpointConfig);
_ = endpoint.StartEndpoint(CancellationToken.None);

var publisher = demo.CreatePublisher(endpointConfig);

await Task.WhenAll([
    publisher.BroadcastAsync(new TestEvent("test 1"), CancellationToken.None),
    publisher.BroadcastAsync(new TestEvent("test 2"), CancellationToken.None),
    publisher.BroadcastAsync(new TestEvent("test 3"), CancellationToken.None),
    publisher.BroadcastAsync(new TestEvent("test 4"), CancellationToken.None),
    publisher.BroadcastAsync(new TestEvent("test 5"), CancellationToken.None)
]);

Console.WriteLine("Press any key to exit");
Console.ReadKey();

// normally this is DI'd
class EndpointProvider : IEndpointProvider
{
    private readonly TestEndpoint testEndpoint = new();
    public object? GetService(Type endpointType) => testEndpoint;
}

More to come

More documentation and examples are on the way. Stay tuned!

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.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on RickDotNet.Apollo:

Package Downloads
RickDotNet.Apollo.Providers.NATS

Distributed messaging library.

RickDotNet.Apollo.Extensions.Microsoft.Hosting

Distributed messaging library.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
0.6.2 77 11/17/2024
0.5.6 76 11/17/2024
0.5.5 88 11/14/2024
0.5.4-preview-1 79 11/13/2024
0.5.3 89 11/12/2024
0.5.2 94 11/2/2024
0.5.1 93 11/2/2024
0.5.0 120 10/15/2024
0.4.4 121 9/22/2024
0.4.3 163 9/16/2024
0.4.2 146 9/14/2024
0.4.1 183 9/10/2024