How to Propagate Feedback from a Class Library to an ASP.Net Client using SignalR
A detailed look at how a callback mechanism at the library backend can be propagated to the web client frontend via SignalR groups
I recently had to figure out how to create a library that provides feedback to the user irrespective of whether the user is a simple .NET Console application or an ASP.Net Web client. The example code I am going to use in this article is vastly simplified, starting with the library:
The SimpleDLLFeedback
provides the core functionality and can be used both from a .NET Console application and from an ASP.Net Core Web API. The client using the API requires to show any feedback from the SimpleDLLFeedback
on a dedicated UI region.
This article describes how to propagate the "SimpleMethod called"
feedback from the SimpleDLLFeedback
to the web client via the Web API layer using SignalR without modifying any code in the DLL. The article focuses only on the Web API layer and simulates the frontend by using:
- the Postman tool - to send a request to the Web API layer
- .Net Console application (HttpClient)- to receive the feedback
"SimpleMethod called"
from theSimpleDLLFeedback
ASP.Net Core Web API Layer
I created a standard ASP.Net Core Web API using the dotnet new webapi
command and deleted the default controller code. I then ran dotnet add package Microsoft.AspNetCore.SignalR
to add the SignalR nuget package and added the SignalR functionality in the Startup.cs
file:
Create the SignalR Hub and store the client connection information
The SignalR Hub named FeedbackNotifierHub
creates a client connection group using the subscriberID as shown below:
The Context.GetHttpContext().Request.Query[subscriberIdTag]
looks for the subid query parameter in the client connection request and uses the value to add the connection to a group identified by the subscriberID Groups.AddToGroupAsync(Context.ConnectionId, subscriberID)
. Using the subscriberID this way allowed me to connect the client request to run a SimpleMethod
via REST API to the “same” client’s http connection to receive the feedback "SimpleMethod called"
via SignalR. It is important to realise that the subid value has to be used in two places:
- In the REST API call made by the Web client
- In the HTTP client connection to the SignalR Hub to receive the feedback
I added the FeedbackNotifierHub
to the Startup.cs
file as follows:
The exact connection URL for a client with a subscriberID of Client1 would be (my local server runs on port 5000):
http://localhost:5000/feedbacknotifierhub?subid=Client1
Use the SimpleDLLFeedback from the ASP.Net Controller
In order to add the SimpleDLLFeedback
to the ASP.Net Controller I first created the NotifyingFeedbackWriter
service:
The INotifyingFeedbackWriter is as follows:
The important thing to notice here is that I could not use the IWriter
interface directly since I needed a way to connect the client REST API call to the “same” client’s HTTP connection to the SignalR Hub. The SetNotifier
method is used for that.
Also notice how the IFeedbackNotifier
pops up in this interface and also as the strongly-typed Hub used in the FeedbackNotifierHub : Hub<IFeedbackNotifier>
. This indicates that the client interface for the SignalR Hub is being used to send the actual feedback notification to the client.
After creating the IWriter
implementation I added the SimpleDLLFeedback
service to the controller:
It is important to add the INotifyingFeedbackWriter
service as a scoped service. I shall come back to that later in the article.
The ISimpleDLLFeedback
is used by the controller as follows:
Well, it turns out that the Controller does not use the SimpleDLLFeedback
directly but rather through a proxy called SimpleDLLFeedbackProxy
. The proxy is just a wrapper to connect the REST API call to simplemethod
to the HTTP client connection to the SignalR Hub via subid which is a required query parameter for the REST API call.
I have also used a Func
object to make the call to SimpleDLLFeedback
“cleaner”. Notice how the SimpleDLLFeedback(subid)
:
- Takes a required parameter - subid
- Returns the actual
SimpleDLLFeedback
object to call theSimpleMethod
on
Create an SimpleDLLFeedbackProxy to connect the calling client to the feedback
The SimpleDLLFeedbackProxy
is as follows:
The proxy takes the following input parameters during instantiation:
- The
INotifyingFeedbackWriter
to set the actual notifier to be used for the feedback - The
IHubContext
to obtain the current client connection using the subid to query the connection group - The
ISimpleDLLFeedback
to return the actual object used to make the call
The only reason I used the proxy is to hide away the fact that every call to the SimpleDLLFeedback
requires the subid to be set first via the REST API call.
The input constructor parameter INotifyingFeedbackWriter
used here will create a new instance in the ASP.Net dependency injection model unless the service is added as a scoped service - which I have already done before. It is extremely important that the same instance is used for the REST API handling and in the creation of the SimpleDLLFeedback
service.
I added the SimpleDLLFeedbackProxy
to the controller:
The Simulated Frontend
Send a request
Now that I have created the ASP.Net WEB API I can just run it using dotnet run
:
After starting the WebServer I sent a REST API GET request http://localhost:5000/simplemethod?subid=Client1
using Postman which returned 200 OK
.
The WebServer output:
Receive the feedback
To receive the feedback SimpleMethod called
from the library, I created a .NET Console application that connects to the SignalR Hub and listens for ReceiveFeedback
calls on the client connection:
I also added the following nuget packages to the HttpClient:
1. dotnet add package Microsoft.AspNetCore.SignalR.Client
2. dotnet add package Microsoft.Extensions.Logging
After starting the server and the HttpClient with the parameter Client1
I see the following on the server console:
After sending a REST API Get request I see the following on the HttpClient console:
All code used in this article can be found in my GitHub repository.
I hope that my article helps others.