RossWright.MetalShout.Server 8.0.0-beta007

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

// Install RossWright.MetalShout.Server as a Cake Tool
#tool nuget:?package=RossWright.MetalShout.Server&version=8.0.0-beta007&prerelease                

Ross Wright's Metal Shout

by Ross Wright

Copyright 2023 Pross Co. All Rights Reserved.

Description

Easily push messages from the server to the client by user.

Pre-requisites

Metal Shout requires Metal Guardian which it uses for managing HTTP connections and authentication. If you have a scenario where you do not need authentication, you're better off implementing your own solution on SignalR. Metal Shout is based on sending objects to a specific user, thus authentication is required to identify the user behind each connected client.

Setup

To setup Metal Shout on the server, add the RossWright.MetalShout.Server package and call: AddMetalShout on the ServiceCollection in Program.cs and call UseMetalShout() after the Build call but before the Run call,

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMetalShout();
...
var app = builder.Build();
...
app.UseMetalShout();
...
app.Run();

Similarly, to setup Metal Shout on the client, add the RossWright.MetalShout package and call: AddMetalShout on the ServiceCollection in Program.cs. If you are using Switchboard (see below) or want the connection to the server to open on login and close on logout, call UseMetalShout() on the built app after the Build call but before the Run call,

var builder = WebAssemblyHostBuilder.CreateBuilder(args);
builder.Services.AddMetalShout();
...
var app = builder.Build();
...
app.UseMetalShout(); //if using Switchboard, or want connection linked to authentication
...
app.Run();

Push Messages

A push message can be an instance of any class known to both the client and server that can be serialized (no circular references, etc.). Note there is a fairly high size limit on messages imposed by SignalR which MetalPush is based on, but the recommended pattern is for messages to contain only the information absolutely neccisary (reference IDs, etc) and have the client retrieve any substantial amount of data via an API.

Pushing Messages from the Server

All messages are pushed to a user. If the user has multiple active clients active, the message will be pushed to all of those clients simultaneously. What users receive a push message can be optionally specified by user ID at the time the message is pushed,

pushService.Push(new MyPushObject(), user.Id);

or by subscribing the user to the type of push message in one place (perhaps on login or when a user enters a chat room) and pushing it in another, separating the concerns of tracking who needs to receive what messages and when the messages need to be sent,

pushService.SubscribeUser<MyPushObject>(user.Id);
...
pushService.Push(new MyPushObject());

Users can also be unsubscribed in a similar fashion,

pushService.UnsubscribeUser<MyPushObject>(user.Id);

Reference IDs

When pushing a message or subscribing a user, an optional reference ID can be specified. This allows you to subscribe a user to receive push messages of a specific typeonly if it is pushed with the specified reference id. Any users subscribed for the push message type without a reference ID will also receive messages pushed with a reference ID. This looks like:

var message = new MyPushObject() { Id = "1234" };
pushService.Push(message, message.Id, user.Id);

or

pushService.SubscribeUser<MyPushObject>(user.Id, "1234");
...
var message = new MyPushObject() { Id = "1234" };
pushService.Push(message, message.Id);

and

pushService.UnsubscribeUser<MyPushObject>(user.Id, "1234");

Subscribe for all reference IDs and users

When subscribing a user you can specify the user should receive all push messages of the type regardless of the reference id or the users the message was sent to. This is useful for administrative users or monitoring dashboards. For performance sake, you should limit the lifetime of such subscriptions to just the period of time it is needed (such as only while the monitoring page is open on a client). This looks like:

pushService.SubscribeUser<MyPushObject>(userOne.Id, forAllRefsAndUsers: true);
...
var message = new MyPushObject() { Id = "1234" };
pushService.Push(message, message.Id, userTwo.Id); // userOne also gets the message

Connection Observation

Even though a user might have logged in, their connection to the server to receive push messages is dependent on having an active subscription on the client-side (see below). MetalShout tracks the connection of each user's clients, but you can hook into Metal Shout to take actions when a user connects (and disconnects) to the server for push messages by registering a service as a IPushConnectionObserver. MetalShout supports multiple observers.

public interface IPushConnectionObserver
{
    Task OnConnected(Guid? userId, bool isFirstConnection);
    Task OnDisconnected(Guid? userId, Exception? exception, bool wasLastConnection);
}

Endpoint Name

The default SignalR Hub Endpoint for Metal Shout is "/PushHub". You can change this by passing a parameter to the AddPushService call on the client and the UsePushService call on the server.

builder.Services.AddMetalShout("MyChatHub");

and

app.UseMetalShout("MyChatHub");

Receiving Push Messages on the Client

To subscribe to receive push messages on the client, there are three ways to use Metal Shout:

Subscribe Using the Push Service

To subscribe to receive push messages using the push service inject 'IPushService and call Subscribe, keeping a reference to the IDisposable momento it returns, implementing IAsyncDisposable on your component and then disposing the momento in your component's DisposeAsync method.

[Inject] public IPushService PushService { get; set; } = null!;
private IAsyncDisposable? _subscription;

protected override async Task OnInitializedAsync()
{
    _subscription = await PushService.Subscribe<MyPushMessage>(OnMyPushMessage),
}

public async ValueTask DisposeAsync()
{
	if (_subscription != null)
	{
		await _subscription.DisposeAsync();
	}
}

private async Task OnMyPushMessage(MyPushMessage msg)
{
	// handle the message, calling StateHasChanged() to re-render the component since this is not a UI-generated call	
}

This method has the benefit that the connection to the server will only be maintained if there is an active subscription.

Using Switchboard

Switchboard is a service provided as part of Metal Core that allows you to send messages within a process. For example, you might send a message from a profile edit screen and subscribe to it from your page header to detect when the currently logged-in user has changed their profile name or avatar and update the UI. This is similar to MediatR Notifications but uses a subscription model instead of a handler model. When Switchboard has been registered as a service, Metal Shout will also broadcast received push messages via the Switchboard.

To setup Switchboard, call AddSwitchboard on the services collection and UseMetalShout on the built app after the Build call but before the Run call in Program.cs,

var builder = WebAssemblyHostBuilder.CreateBuilder(args);
builder.Services.AddMetalShout();
builder.Services.AddSwitchboard();
...
var app = builder.Build();
...
app.UseMetalShout();
...
app.Run();

and to subscribe to receive messages on the Switchboard in a component, inject ISwitchboard and call Subscribe keeping a reference to the IDisposable momento it returns, implementing IDisposable on your component and then disposing the momento in your component's Dispose method.

[Inject] public ISwitchboard Switchboard { get; set; } = null!;
private IDisposable? _subscription;

protected override void OnInitialized()
{
    _subscription = Switchboard.Subscribe<MyPushMessage>(OnMyPushMessage),
}

public void Dispose()
{
	if (_subscription != null)
	{
		_subscription.Dispose();
	}
}

private async Task OnMyPushMessage(MyPushMessage msg)
{
	// handle the message, calling StateHasChanged() to re-render the component since this is not a UI-generated call	
}

A benefit of subscribing to push messages via the Switchboard is that in addition to receiving pushes from the server you can also send the same message from code in the client.

[Inject] public ISwitchboard Switchboard { get; set; } = null!;
...
private async Task OnClick()
{
	await Switchboard.SendAsync(new MyPushMessage());
}

Subscribe using an IPushSubscriber

If you need a reusable subscription handler, you can implement IPushSubscriber,

public class PushObjSubscriber : IPushSubscriber<MyPushMessage>
{
	public Task OnPushReceived(MyPushMessage message)
	{
		// process the incoming push object here
	}
}

and then where appropriate, you can call subscribe with an instance of your Push Subscriber

[Inject] public IPushService PushService { get; set; } = null!;
...
var subscriber = new PushObjSubscriber();
await PushService.Subscribe(subscriber);

and then when you no longer need the push subscriber,

await pushService.Unsubscribe(subscriber);

Using multiple servers

The examples above assume the client is connecting to a server on the default connection as setup by AddMetalGuardianHttpClient. To connect to a different server, pass the connection name provided to Metal Guardian to IPushService.Subscribe and IPushService.Unsubscribe.

For Switchboard, UseMetalShout also accepts a connectionName parameter, but messages of the same type from any connection are pushed to all subscribers for that type. If your handler needs to know which connection a message has come from either use the IPushService subscription methods to limit the messages recieve by your handler to one connection or encode that information in your message.

Licensing

A license must be purchased to use RossWright.Metal libaries in a production environment. For development enviroments, using the libraries without a license will show a console message on initialization and cease functioning after one hour. To install your license file include it in the executable project with the Build Action set to Embedded Resource. The file can be renamed as needed, but must end with the extension .license.

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 (1)

Showing the top 1 NuGet packages that depend on RossWright.MetalShout.Server:

Package Downloads
RossWright.MetalGrind.Server

MetalGrind Server-side

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
8.0.0-beta016 31 10/23/2024
8.0.0-beta015 34 10/23/2024
8.0.0-beta014 49 10/19/2024
8.0.0-beta007 61 9/28/2024