Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
147787 stories
·
32 followers

Using SignalR with Wolverine 5.0

1 Share

The Wolverine 5.0 release earlier last last week (finally) added a long requested SignalR transport.

The SignalR library from Microsoft isn’t hard to use from Wolverine for simplistic WebSockets or Server Sent Events usage as it was, but what if you want a server side application to exchange any number of different messages between a browser (or other WebSocket client because that’s actually possible) and your server side code in a systematic way? To that end, Wolverine now supports a first class messaging transport for SignalR. To get started, just add a Nuget reference to the WolverineFx.SignalR library:

dotnet add package WolverineFx.SignalR

There’s a very small sample application called WolverineChat in the Wolverine codebase that just adapts Microsoft’s own little sample application to show you how to use Wolverine.SignalR from end to end in a tiny ASP.Net Core + Razor + Wolverine application. The server side bootstrapping is at minimum, this section from the Wolverine bootstrapping within your Program file:

builder.UseWolverine(opts =>
{
    // This is the only single line of code necessary
    // to wire SignalR services into Wolverine itself
    // This does also call IServiceCollection.AddSignalR()
    // to register DI services for SignalR as well
    opts.UseSignalR(o =>
    {
        // Optionally configure the SignalR HubOptions
        // for the WolverineHub
        o.ClientTimeoutInterval = 10.Seconds();
    });
    
    // Using explicit routing to send specific
    // messages to SignalR. This isn't required
    opts.Publish(x =>
    {
        // WolverineChatWebSocketMessage is a marker interface
        // for messages within this sample application that
        // is simply a convenience for message routing
        x.MessagesImplementing<WolverineChatWebSocketMessage>();
        x.ToSignalR();
    });
});

And a little bit down below where you configure your ASP.Net Core execution pipeline:

// This line puts the SignalR hub for Wolverine at the 
// designated route for your clients
app.MapWolverineSignalRHub("/api/messages");

On the client side, here’s a crude usage of the SignalR messaging support in raw JavaScript:

// Receiving messages from the server
connection.on("ReceiveMessage", function (json) {
    // Note that you will need to deserialize the raw JSON
    // string
    const message = JSON.parse(json);

    // The client code will need to effectively do a logical
    // switch on the message.type. The "real" message is 
    // the data element
    if (message.type == 'ping'){
        console.log("Got ping " + message.data.number);
    }
    else{
        const li = document.createElement("li");
        document.getElementById("messagesList").appendChild(li);
        li.textContent = `${message.data.user} says ${message.data.text}`;
    }
});

and this code to send a message to the server:

document.getElementById("sendButton").addEventListener("click", function (event) {
    const user = document.getElementById("userInput").value;
    const text = document.getElementById("messageInput").value;

    // Remember that we need to wrap the raw message in this slim
    // CloudEvents wrapper
    const message = {type: 'chat_message', data: {'text': text, 'user': user}};

    // The WolverineHub method to call is ReceiveMessage with a single argument
    // for the raw JSON
    connection.invoke("ReceiveMessage", JSON.stringify(message)).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

I should note here that we’re utilizing Wolverine’s new CloudEvents support for the SignalR messaging to Wolverine, but in this case the only single elements that are required are data and type. So if you had a message like this:

public record ChatMessage(string User, string Text) : WolverineChatWebSocketMessage;

Your JSON envelope that is sent from the server to the client through the new SignalR transport would be like this:

{ “type”: “chat_message”, “data”: { “user”: “Hank”, “text”: “Hey” } }

For web socket message types that are marked with the new WebSocketMessage interface, Wolverine is using kebab casing of the type name for Wolverine’s own message type name alias under the theory that that naming style is more or less common in JavaScript world.

I should also say that a first class SignalR messaging transport for Wolverine has been frequently requested over the years, but I didn’t feel confident building anything until we had more concrete use cases with CritterWatch. Speaking of that…

How we’re using this in CritterWatch

The very first question we got about this feature was more or less “why would I care about this?” To answer that, let me talk just a little bit about the ongoing development with JasperFx Software’s forthcoming “CritterWatch” tool:

CritterWatch is going to involve a lot of asynchronous messaging and processing between the web browser client, the CritterWatch web server application, and the CritterStack (Wolverine and/or Marten in this case) systems that CritterWatch is monitoring and administrating. The major point here is that we need to issue a about three dozen different command messages from the browser to CritterWatch that will kick off long running asynchronous processes that will trigger workflows in other CritterStack systems that will eventually lead to CritterWatch sending messages all the way back to the web browser clients.

The new SignalR transport also provides mechanisms to get the eventual responses back to the original Web Socket connection that triggered the workflow and several mechanisms for working with SignalR connection groups as well.

Using web sockets gives us one single mechanism to issue commands from the client to the CritterWatch service, where the command messages are handled as you’d expect by Wolverine message handlers with all the prerequisite middleware, tracing, and error handling you normally get from Wolverine as well as quick access to any service in your server’s IoC container. Likewise, we can “just” publish from our server to the client through cascading messages or IMessageBus.PublishAsync() without any regard for whether or not that message is being routed through SignalR or any other message transport that Wolverine supports.

Web Socket Publishing from Asynchronous Marten Projection Updates

It’s been relatively common in the past year for me to talk through the utilization of SignalR and Web Sockets (or Server Side Events) to broadcast updates from asynchronously running Marten projections.

Let’s say that you have an application using event sourcing with Marten and you use the Wolverine integration with Marten like this bit from the CritterWatch codebase:

        opts.Services.AddMarten(m =>
        {
            // Other stuff..

            m.Projections.Add<CritterServiceProjection>(ProjectionLifecycle.Async);
        })
            // This is the key part, just calling IntegrateWithWolverine() adds quite a few 
            // things to Marten including the ability to use Wolverine messaging from within
            // Marten RaiseSideEffects() methods
            .IntegrateWithWolverine(w =>
        {
            w.UseWolverineManagedEventSubscriptionDistribution = true;
        });

We have this little message to communicate to the client when configuration changes are detected on the server side:

    // The marker interface is just a helper for message routing
    public record CritterServiceUpdated(CritterService Service) : ICritterStackWebSocketMessage;

And this little bit of routing in Wolverine:

opts.Publish(x =>
{
x.MessagesImplementing<ICritterStackWebSocketMessage>();
x.ToSignalR();
});

And we have a single stream projection in CritterWatch like this:

public class CritterServiceProjection 
    : SingleStreamProjection<CritterService, string>

And finally, we can use the RaiseSideEffects() hood that exists in the Marten SingleStream/MultiStreamProjection to run some code every time an aggregated projection is updated:

    public override ValueTask RaiseSideEffects(IDocumentOperations operations, IEventSlice<CritterService> slice)
    {
        // This is the latest version of CritterService
        var latest = slice.Snapshot;
        
        // CritterServiceUpdated will be routed to SignalR,
        // so this is de facto updating all connected browser
        // clients at runtime
        slice.PublishMessage(new CritterServiceUpdated(latest!));
        
        return ValueTask.CompletedTask;
    }

And after admittedly a little bit of wiring, we’re at a point where we can happily send messages from asynchronous Marten projections through to Wolverine and on to SignalR (or any other Wolverine messaging mechanism too of course) in a reliable way.

Summary

I don’t think that this new transport is necessary for simpler usages of SignalR, but could be hugely advantageous for systems where there’s a multitude of logical messaging back and forth from the web browser clients to the backend.



Read the whole story
alvinashcraft
2 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Wolverine 5.0 is Here!

1 Share

That’s of course supposed to be a 1992 Ford Mustang GT with the 5.0L V8 that high school age me thought was the coolest car I could imagine ever owning (I most certainly never did of course). Queue “Ice, Ice Baby” and sing “rolling, in my 5.0” in your head because here we go…

Wolverine 5.0 went live on Nuget earlier today after about three months of pretty intensive development from *20* different contributors with easily that many more folks having contributed to discussions and GitHub issues that helped get us here. I’m just not going to be able to list everyone, so let me just thank the very supportive Wolverine community, the 19 other contributors, and the JasperFx clients who contributed to this release.

This release came closely on the heels of Wolverine 4.0 earlier this year, with the primary reasons for a new major version release being:

  • A big change in the internals as we replaced the venerable TPL DataFlow library with the System.Threading.Channels library in every place that Wolverine uses in memory queueing. We did this as a precursor to a hugely important new feature commissioned by a JasperFx Software client (who really needs to get that feature in for their “scale out” so it was definitely about time I got this out today).
  • Some breaking API changes in the “publinternals” of Wolverine to support “CritterWatch”, our long planned and I promise finally in real development add on tooling for Critter Stack observability and management

With that being said, the top line new changes to Wolverine that I’ll be trying to blog about next week are:

For a partial list of significant, smaller improvements:

  • Wolverine can utilize Marten batch querying for the declarative data access, and that includes working with multiple Marten event streams in one logical operation. This is part of the Critter Stack’s response to the “Dynamic Consistency Boundary” idea from some of the commercial event sourcing tools
  • You can finally use strong typed identifiers with the “aggregate handler workflow”
  • An overhaul of the dead letter queue administration services that was part of our ongoing work for CritterWatch
  • A new tutorial for dealing with concurrency when building against Wolverine
  • Optimistic concurrency support for EF Core backed Sagas from the community
  • Ability to target multiple Azure Service Bus namespaces from a single application and improvements to using Azure Service Bus namespace per tenant
  • Improvements to Rabbit MQ for advanced usage

What’s Next?

As happens basically every time, several features that were planned for 5.0 and some significant open issues didn’t make the 5.0 cut. The bigger effort to optimize the cold start time for both Marten and Wolverine will hopefully happen later this year. I think the next minor point release will target some open issues around Wolverine.HTTP (multi-part uploads, actual content negotiation) and the Kafka transport. I would like to take a longer look sometime at how the CritterStack combination can better support operations that cross stream boundaries.

But in the meantime, I’m shifting to open Marten issues before hopefully spending a couple weeks trying to jump start CritterWatch development again.

I usually end these kinds of major release announcements with a link to Don’t Steal My Sunshine as an exhortation to hold off on reporting problems or asking for whatever didn’t make the release. After referring to “Ice, Ice Baby” in the preface to this and probably getting that bass line stuck in your head, here’s the song you want to hear now anyway — which I feel much less of after getting this damn release out:



Read the whole story
alvinashcraft
2 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Introducing vibe coding in Google AI Studio

1 Share
Introducing vibe coding in Google AI Studio
Read the whole story
alvinashcraft
4 hours ago
reply
Pennsylvania, USA
Share this story
Delete

MCP servers and the role tech writers can play in shaping AI capabilities and outcomes -- podcast with Fabrizio Ferri Beneditti and Anandi Knuppel

1 Share
In this podcast episode, Fabrizio Ferri Benedetti and I chat with guest Anandi Knuppel about MCP servers and the role that technical writers can play in shaping AI capabilities and outcomes. Anandi shares insights on how writers can optimize documentation for LLM performance and expands on opportunities to collaborate with developers around AI tools. Our discussion also touches on ways to automate style consistency in docs, and the future directions of technical writing given the abundance of AI tools, MCP servers, and the central role that language plays in it all.

Read the whole story
alvinashcraft
4 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Updating our Blazor site to .NET 10! 🦝 oct 23

1 Share
From: Coding After Work
Duration: 2:29:06
Views: 21

Broadcasted live on Twitch -- Watch live at https://www.twitch.tv/codingafterwork

Read the whole story
alvinashcraft
4 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Things to Do in Philadelphia This Week & Weekend

1 Share

We’re not quite ready to swap rustling candy wrappers for rustling leaves, but this week’s list of things to do in Philadelphia is already ramping up the fall fun.

It’s Halloween, baby! Philly goes all out with Halloween events for kids, grown-ups and kids at heart like Halloween Haunts at Stateside Live! (Friday), the Haunted Circus at Philadelphia School of Circus Arts (Saturday) and the Halloween Little Tot Parade in Spruce Hill (Friday).

Shifting back to soup mode, this week features annual traditions like Apple Festival in Peddler’s Village (Saturday & Sunday) and Día de los Muertos events throughout the city (Saturday & Sunday), along with off-the-beaten-path fests like the 2025 Pierogi Festival at St. Nicholas Eastern Orthodox Church (Saturday & Sunday) and the Philly Flannel Festival at Braid Mill (Sunday).

And it’s curtain call for several theater shows, including Kimberly Akimbo at the Academy of Music (through Sunday) and Million Dollar Quartet at Walnut Street Theatre (through Sunday).

Plus, your last chance to frolic at seasonal harvest fests like FallFest at Shady Brook Farm (through Thursday) and Pumpkinland at Linvilla Orchards (through Sunday).

Also happening this week: Halsey at The Fillmore (Thursday), CraftMONTH 2025 (begins Thursday), the start of Native American Heritage Month (begins Saturday) and the opening of Afrofuturism in Costume Design at the African American Museum in Philadelphia — with a showcase by Black Panther’s own costume designer (opens Saturday).

With so much happening this week, you’ll wanna stay over — so why pay more? Book the Visit Philly Overnight Package for free hotel parking and priceless peace of mind.

Below, find the best things to do in Philadelphia this week and weekend, October 27 to November 2, 2025.

Read the whole story
alvinashcraft
5 hours ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories