Chat Application using Aurelia and SignalR

Hello and welcome! You have definitely heard of SignalR for real-time web applications, in this post I want to help you write a simple traditional chat application using SignalR and my favorite SPA framework Aurelia. You can download the source code from my GitHub, here, notice that in this sample we use WebPack for bundling.

We need to create a new solution in which we have both ASP.NET Core and Aurelia configured; thus I use AureliaToolbelt.AspNetCore::1.2.1 spa template, it was created by Aurelia CLI, you must install it beforehand:

Shell

1

2

3

dotnet new--install AureliaToolbelt.AspNetCore::1.2.1

or use your own preferred choice, for instance, Aurelia CLI, then, create a directory named SignalRChatApp and run the following command:

Shell

1

2

3

dotnet newaut

it takes some time to have all dependencies installed, let’s wait 🙂

Well, this application is two fold: Backend using asp.net core and SignalR and frontend using Aurelia. Let’s begin with the former.

Backend, SignalR Hubs

We need to bootstrap SignalR so that we can create hubs and connect to them via a valid URL that we have defined. Hubs are the endpoints in SignalR abstracting the underlying connection layer for real-time communication; that could be WebSockets, or long polling or etc.

First, we need to tell the DI system which services we require, to do that add the following code in ConfigureServices method in the Startupclass:

C#

1

2

3

services.AddSignalR();

then, add SignalR middleware to the pipeline, bear in mind to add SignalR’s middleware before the MVC middleware, if not, make sure that your SignalR’s routes will not be caught by MVC routes.

C#

1

2

3

4

5

app.UseSignalR(routes=>{

routes.MapHub<ChatHub>("/chat");

});

In the previous code snippet, we register a route for our chat room endpoint,/chat, map it to a hub named ChatHub, it’s time for our hub.

Create a folder in the root directory and name it Hubs, then create a C# class, ChatHub.cs, copy the following snippet:

We created a hub with a simple method taking two arguments, sender and the message, which is called from client application later on, and will call the updateMessage on all clients connecting to this endpoint. Now, it’s time to take a look at the other side of the argument, client, Aurelia.

Aurelia, Front-end player

The main player here is a service which is responsible for the communication between our Aurelia app and ChatHub, chat-hub-service.ts, BTW I am a fan of typescript so that’ll be used. And since I never like an application without authorization, I implemented a fake authentication in this demo and its implemented by using AuthorizeStep in conjunction with another service, auth-service.ts; the latter is a class with methods and properties to ease the login process, for now, it just checks localStorage for the logged-in user, you can then replace it with a more complex service which checks for instance through an identity server, it has two methods, loginand logout,and two properties.

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

import{singleton}from"aurelia-framework";

@singleton()

exportclassAuthService{

private loggedInKey:string="logged-in";

publicget isLoggedIn():boolean{

returnlocalStorage.getItem(this.loggedInKey)?true:false;

}

publicget username(){

returnlocalStorage.getItem(this.loggedInKey);

}

publiclogin(username:string):Promise<boolean>{

returnnewPromise(resolve=>{

localStorage.setItem(this.loggedInKey,username);

resolve(true);

});

}

publiclogout():Promise<boolean>{

returnnewPromise(resolve=>{

localStorage.removeItem(this.loggedInKey);

resolve(true);

});

}

}

We require this service in multiple places, first of which is our Authorization step within Aurelia’s pipeline, change your app.ts file to the following, I have App class and AuthorizeStep class in the same file, that would be better if you have them in separate files.

As you can see in the above code snippet, we have two routes configured, login, and chat-room which requires authentication, that means when we add an authorize step in the Aurelia pipeline and set the auth property of a rout to true, then that step is responsible for validating if the user is currently authenticated or not, in this case the authorization step uses AuthService‘s isLoggedIn property for validation; if fails, it will redirect the user to login page.

The next step is to declare a class which is responsible to communicate with the hub, that’s chat-hub-service.ts

I have to mention that this service is a singleton so that only one instance will be available in the whole application, but what if we need multiple places to be notified when a message received? That lies in the heart of using EventAggregator and that is in the notifier method, you need to update constructor to inject( autoinject ) an instance of EventAggregator

Now wherever we need to get messages from the server side hub we can use EventAggregator to subscribe to Message-Received event, and we’ll be notified. Thanks to Aurelia messaging system :smile: .

There’s still on thing left, we have created our connection, we have not connected to the hub though. you need to call startmethod on your connection, hence I create a start method within the ChatHubService in order for users of this service to be able to start the connection on demand. The same goes for stopping the connection, in the above-mentioned methods we return promises, that enables the clients of the service to register callbacks to handle failure and success.

The last piece of code for this service enables us to send messages from client to server, in other words calling server methods on our hub from our Aurelia application. You should call the invoke method on your connection, the first parameter is the name of the method on your C# hub, and the rest are the input parameters for that method, they should match the server side method arguments respectively.

Instances of AuthService,ChatHubServiceand Router are injected. Inside the canActivate method we check whether it is possible to start the connection, if not, we won’t route to this page, a better approach could be displaying an alert message; otherwise, we subscribe to Message-Receivedevent in order to be notified when a message pushed from the server via this connection. On addMessage click_handler we use injected chat-hub-service to publish messages to the server which will then push them back to all the connected clients.

On our detached method we just stopour connection, one may not need to do so, to show notification toasts for instance on receiving messages.

The htmlpart consists of a text box binding to the message property, and a button's click bound to addMessge. <li>elements create for each message received from the server.