5

SignalR event aggregation with Blazor WASM | Anders Malmgren

 2 years ago
source link: https://andersmalmgren.com/2021/02/19/signalr-event-aggregation-with-blazor-wasm/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

SignalR event aggregation with Blazor WASM

As you probably know by now I love event aggregation and being able to seamless forward server side events to clients. My library SignalR.EventAggregatorProxy have been around for a while now and it enables seamless event aggregation between server and client. The .NET core client library just got updated to .NET 5. And as it turns out it works without any effort in Blazor WASM.

In your WASM client project add nuget package SignalR.EventAggregatorProxy.Client.DotNetCore. Next up we need to config the event aggregator client and this is done using the standard service pipeline from the WASM client app Program.cs.

builder.Services.AddSignalREventAggregator()
.WithHubUrl($"{builder.HostEnvironment.BaseAddress}EventAggregatorProxyHub")
.OnConnectionError(e => Debug.WriteLine(e.Message))
.Build()
.AddSingleton<IEventAggregator>(p => p.GetService<IProxyEventAggregator>())
.AddSingleton<IEventTypeFinder, EventTypeFinder>()
.AddTransient<EventsViewModel>()
.AddTransient<SendMessageViewModel>();

This code is pretty much identical to the standalone .NET 5 desktop configuration, which on its own is pretty awesome. First I point out the url to the SignalR hub. I also add IEventAggregator so that I can publish and subscribe to events from the viewmodels. We also point out the custom IEventTypeFinder which tells the library which events are available to it. What’s cool is that we can share the same events contracts assembly between Blazor WASM and the server, this means with zero effort we get a strongly typed contract between server and client, something that’s not as easy with classic javascript/typescript web solutions. Finally I register my viewmodels for the demo application.

Subscribing to events are done exactly like the vanilla desktop library

public class EventsViewModel : IHandle<StandardEvent>, IHandle<GenericEvent<string>>, IHandle<ConstrainedEvent>, IHandle<ClientSideEvent>
{
public EventsViewModel(IProxyEventAggregator eventAggregator)
{
Events = new List<IMessageEvent<string>>();
eventAggregator.Subscribe(this, builder =>
builder.For<ConstrainedEvent>()
.Add(new ConstrainedEventConstraint {Message = "HelloWorld"}));
}
public List<IMessageEvent<string>> Events { get; }
public Action StateHasChanged { get; set; }
public void Handle(StandardEvent message)
{
Add(message);
}
public void Handle(GenericEvent<string> message)
{
Add(message);
}
public void Handle(ConstrainedEvent message)
{
Add(message);
}
public void Handle(ClientSideEvent message)
{
Add(message);
}
private void Add(IMessageEvent<string> message)
{
Events.Add(message);
StateHasChanged();
}
}

We have come far in web development when we can use conventions like these. You implement interface IHandle<TEvent> and it will get called when server publishes such a message. From the constructor you subscribe to events. We also have a mechanic to constraint events, in this case the client will only receive events of type ConstrainedEvent when property Message = HelloWorld.

Finally we inject the view models into the razor view using DI.

@inject SendMessageViewModel SendMessage
@inject EventsViewModel Events

Used like

@foreach (var message in Events.Events)
{
<div>@message.Message</div>
}

Since events can come in at any time we need to call StateHasChanged to ensure that UI is updated correctly. Since we update the event collection from a injected service we need to hook up a reference to the razor view StateHasChanged.

@code {
protected override void OnInitialized()
{
base.OnInitialized();
Events.StateHasChanged = StateHasChanged;
}
}

Not very elegant, I have started a feature request ticket for adding mechanics to inject component context and be able to call StateHasChanged from here.

Full demo code found here


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK