DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • GenAI-Powered Automation and Angular
  • Upload and Retrieve Files/Images Using Spring Boot, Angular, and MySQL
  • How to Use Augury to Check Lazy Loading in Angular 8
  • How to Create a Nested Grid Using Angular 8

Trending

  • My LLM Journey as a Software Engineer Exploring a New Domain
  • Scalable, Resilient Data Orchestration: The Power of Intelligent Systems
  • Medallion Architecture: Efficient Batch and Stream Processing Data Pipelines With Azure Databricks and Delta Lake
  • How AI Agents Are Transforming Enterprise Automation Architecture
  1. DZone
  2. Coding
  3. Frameworks
  4. Creating a Web Chat with SignalR, Web Sockets, Angular and Magic

Creating a Web Chat with SignalR, Web Sockets, Angular and Magic

With good abstractions everything is simple. Changing gears on your car probably involves thousands of moving parts, but still it's dead simple to achieve

By 
Thomas Hansen user avatar
Thomas Hansen
DZone Core CORE ·
Jun. 02, 21 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
11.4K Views

Join the DZone community and get the full member experience.

Join For Free

Web Sockets and asynchronous message transmissions over socket connections is probably one of the most difficult tasks you can possibly do in any web application. Hence, to make it manageable, it needs to be simplified, the same way the gearbox in your car is simple to use, even though it probably involves thousands of moving parts. In this article I will walk you through how to create a live chat client using SignalR, Web Sockets and Magic. If you wish to follow the tutorial though, the first thing you'll have to do is to download Magic.

The Angular frontend

First we'll need a frontend. Use the Angular CLI to create a new Angular project and name it "chat". Open a terminal on your development machine and execute the following command in it.


Shell
 
ng new chat


You can choose whatever setting you wish, but I chose the following as I went through the questions.

  1. No routing
  2. SCSS

Change into this folder in your terminal using cd chat, and use for instance Visual Studio Code to open the folder. If you have the Visual Studio Code command line binding, you can do this by typing code ./ into your terminal. Then we'll need a terminal window in VS Code. You can open a new terminal window through the "Terminal" menu item. Type the following command into your VS Code terminal window.


Shell
 
npm link


This ensures we link in all packaged our project depends upon. This might take some time. Afterwards we'll need to add the client side SignalR package. Execute the following command in your terminal window.


Shell
 
npm install @aspnet/signalr


Now we can serve our project with the following command.


Shell
 
ng serve --port 4201


The reason why we need to override the port, is because the Magic Dashboard is probably already running on the default port which is 4200. You can now visit localhost:4201 to see your app. Open the "app.component.html" file in the folder "/src/app/" and replace its existing code with the following HTML.


HTML
 
<div>
  <h1>Chat client</h1>
  <textarea id="" cols="30" rows="10" [(ngModel)]="message">{{message}}</textarea>
  <br />
  <button (click)="send()">Submit</button>
  <br />
  <textarea id="" cols="30" rows="10" [(ngModel)]="content"></textarea>
</div>


Notice, the UI isn't all that marvellous, but to keep the tutorial relevant to only SignalR and web sockets, we'll ignore this. If you wish to create a better UI you might benefit from reading up about Angular Material. However, if you saved your above HTML file, you've now got a couple of compiler errors. This is because we are using fields on our AppComponent class that still doesn't exist. Modify your "app.component.ts" file to resemble the following.


TypeScript
 
import {
  Component,
  OnDestroy,
  OnInit
} from '@angular/core';

import {
  HttpTransportType,
  HubConnection,
  HubConnectionBuilder
} from '@aspnet/signalr';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {

  content = '';
  message = '';
  hubConnection: HubConnection;

  ngOnInit() {
    let builder = new HubConnectionBuilder();
    this.hubConnection = builder.withUrl('http://localhost:55247/sockets', {
      skipNegotiation: true,
      transport: HttpTransportType.WebSockets,
    }).build();
    this.hubConnection.start();
    this.hubConnection.on('chat.new-message', (args) => {
      this.content += JSON.parse(args).message + '\r\n\r\n';
    });
  }
  
  ngOnDestroy() {
    this.hubConnection.stop();
  }

  send() {
    this.hubConnection.invoke(
      'execute',
      '/tutorials/add-chat',
      JSON.stringify({
        message: this.message,
      }));
    this.message = '';
  }
}


Notice - You might have to change the URL above to http://localhost:5555/sockets if you installed Magic using the Docker images.

The above code ensure we are initialising SignalR as the component is initialised, and that we are disconnecting SignalR as the component is destroyed - In addition to that we are transmitting new chat messages over our SignalR connection as the user clicks the "Submit" button. Then we'll need to import the FormsModule which you can do by modifying your "app.module.ts" file to contain the following code.


TypeScript
 
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


And we are done with our frontend. Save all your files, and let's move onwards to our backend.

Your Hyperlambda SignalR backend

If you click the "Submit" button, you will see that your console window gives you an error. This is because we have still not yet created our backend file responsible for executing as we submit chat messages to the server. Open up your Magic Dashboard with the localhost:4200 URL in a different browser window, log in with your root account, and open the "IDE" menu item. Then do exactly as follows.

  1. Click the "modules" folder
  2. Click the "New" button
  3. Type "tutorials" into the textbox
  4. Check the "Folder" checkbox to make sure we create a folder and not a file
  5. Click "Create"

This creates a new folder called "tutorials" inside your "modules" folder. Then do exactly as follows.

  1. Click the "tutorials" folder
  2. Click the "New" button
  3. Type "add-chat.socket.hl" into the textbox
  4. Click "Create"

This creates a new Hyperlambda file for you. This file will be resolved as the above send() Angular method is invoked over our SignalR web socket connection. Paste in the following into your file.


Plain Text
 
.arguments
   message:string
unwrap:x:+/*/*
sockets.signal:chat.new-message
   args
      message:x:@.arguments/*/message


Then save your file, and switch back to your chat client browser window, and try writing something into the textarea and click "Submit".

Internals

As I started out with, web sockets are a bidirectional transport channel, implying we can both send and receive data over a socket. In the above send() method we are pushing data to the server. The above [sockets.signal] Hyperlambda slot transmits this message to all subscribers again. In our above Angular code we are subscribing to these messages with the following TypeScript.


TypeScript
 
this.hubConnection.on('chat.new-message', (args) => {
  this.content += JSON.parse(args).message + '\r\n\r\n';
});


This ensures that all clients having connected to our web socket backend registering interest in the above messages, will be notified every time the message is published by our Hyperlambda.  If you wish, you can open up multiple browser windows simultaneously and point them to localhost:4201, and write something into any chat, and see how the message instantly is received in all browser windows.

Endpoint resolving

One crucial point which separates the Hyperlambda web sockets implementation from other SignalR implementations, is the dynamic endpoint resolving. What this implies is that the file called "add-chat.socket.hl" is dynamically executed due to our invocation in the following Angular code.


TypeScript
 
this.hubConnection.invoke('execute', '/tutorials/add-chat', JSON.stringify({
   message: this.message,
}));


Notice how the second argument resembles the relative path of the file. What the endpoint resolver will do, is roughly to add ".sockets.hl" to the relative URL specified, load this file dynamically, add the input arguments, and execute its Hyperlambda. This gives us a way to dynamically execute Hyperlambda files to respond to incoming SignalR messages. In addition it gives us the same method to declare arguments and pass in arguments to our SignalR invocations as we would use for normal HTTP REST invocations - Which of course makes it much simpler to consume and learn as you start out with web sockets in Magic.

Wrapping up

In this tutorial we created an Angular chat client. For transport we used SignalR, and on the server side we used dynamically resolved Hyperlambda files to receive messages. In addition we published our messages over a SignalR / Web Sockets connection, to allow multiple clients chat with each other in real time.

AngularJS Visual Studio Code

Published at DZone with permission of Thomas Hansen. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • GenAI-Powered Automation and Angular
  • Upload and Retrieve Files/Images Using Spring Boot, Angular, and MySQL
  • How to Use Augury to Check Lazy Loading in Angular 8
  • How to Create a Nested Grid Using Angular 8

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!