<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Yan Jin</title>
    <description>The latest articles on Forem by Yan Jin (@yjin81).</description>
    <link>https://forem.com/yjin81</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F653537%2Fe9b6bea0-f3d0-4de9-9c5a-bfb3ceb557e8.png</url>
      <title>Forem: Yan Jin</title>
      <link>https://forem.com/yjin81</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/yjin81"/>
    <language>en</language>
    <item>
      <title>Protect Your SignalR Service Based Real-time Application with Application Gateway </title>
      <dc:creator>Yan Jin</dc:creator>
      <pubDate>Tue, 27 Jul 2021 08:42:38 +0000</pubDate>
      <link>https://forem.com/azure/protect-your-signalr-service-based-real-time-application-with-application-gateway-31cf</link>
      <guid>https://forem.com/azure/protect-your-signalr-service-based-real-time-application-with-application-gateway-31cf</guid>
      <description>&lt;p&gt;By &lt;a href="https://docs.microsoft.com/azure/azure-signalr/howto-private-endpoints" rel="noopener noreferrer"&gt;using the Azure Private Endpoint for your Azure SignalR&lt;/a&gt;, it allows clients on a virtual network (VNet) to securely access data over a &lt;a href="https://docs.microsoft.com/en-us/azure/private-link/private-link-service-overview" rel="noopener noreferrer"&gt;Private Link&lt;/a&gt;. As next step, let’s learn how to use the &lt;a href="https://docs.microsoft.com/en-us/azure/application-gateway/overview" rel="noopener noreferrer"&gt;Azure Application Gateway&lt;/a&gt; for your Azure SignalR to manage the real-time traffic.  &lt;/p&gt;

&lt;p&gt;Azure Application Gateway is a web traffic load balancer that enables you to manage traffic to your web applications. Using the Azure Application Gateway with Azure SignalR Service enables you to:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protect your applications from common web vulnerabilities.
&lt;/li&gt;
&lt;li&gt;Get application-level load-balancing for your scalable and highly available applications.
&lt;/li&gt;
&lt;li&gt;Setup end to end secure. &lt;/li&gt;
&lt;li&gt;Customize the domain name. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s go through the key steps together and learn how to implement this reference solution:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Application Gateway helps you protect your applications and setup end to end secure.
&lt;/li&gt;
&lt;li&gt;The client cannot access the Azure SignalR Service instance through public network, and all the traffic is managed through Application Gateway.
&lt;/li&gt;
&lt;li&gt;The traffic between App Service and SignalR Service is also protected by Virtual Network. 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298568i2D82DD50A2A0BCCA%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="High level digram"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setup the Virtual Network
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create the &lt;a href="https://azure.microsoft.com/services/virtual-network" rel="noopener noreferrer"&gt;Virtual Network&lt;/a&gt; &lt;strong&gt;&lt;em&gt;VN1&lt;/em&gt;&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;There is a default subnet already created, and add 2 new subnets:

&lt;ul&gt;
&lt;li&gt;Subnet &lt;strong&gt;&lt;em&gt;applicationSN&lt;/em&gt;&lt;/strong&gt; for your &lt;a href="https://azure.microsoft.com/services/app-service/" rel="noopener noreferrer"&gt;App Service&lt;/a&gt; or &lt;a href="https://azure.microsoft.com/services/functions/" rel="noopener noreferrer"&gt;Azure Functions&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Subnet &lt;strong&gt;&lt;em&gt;gatewaySN&lt;/em&gt;&lt;/strong&gt; for Application Gateway. 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298570iDE77A06747CD74F6%2Fimage-dimensions%2F499x186%3Fv%3Dv2" alt="Virtual Network Configuration"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setup SignalR Service
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create the resource of Azure SignalR Service &lt;strong&gt;&lt;em&gt;ASRS1&lt;/em&gt;&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;&lt;em&gt;ASRS1&lt;/em&gt;&lt;/strong&gt; in the portal. &lt;/li&gt;
&lt;li&gt;Go to the Private endpoint connections blade, and create a new private endpoint &lt;strong&gt;&lt;em&gt;PE1&lt;/em&gt;&lt;/strong&gt; with the &lt;strong&gt;&lt;em&gt;VN1&lt;/em&gt;&lt;/strong&gt; and its &lt;strong&gt;&lt;em&gt;default subnet&lt;/em&gt;&lt;/strong&gt;. Learn more details about &lt;a href="https://docs.microsoft.com/en-us/azure/azure-signalr/howto-private-endpoints" rel="noopener noreferrer"&gt;use private endpoint for Azure SignalR Service&lt;/a&gt;. 

&lt;ul&gt;
&lt;li&gt;Resource &lt;/li&gt;
&lt;li&gt;Resource Type: Microsoft.SignalRService/SignalR &lt;/li&gt;
&lt;li&gt;Resource: &lt;strong&gt;&lt;em&gt;ASRS1&lt;/em&gt;&lt;/strong&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298573i3C7FBE9B69E8FA15%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="SignalR Service Resource"&gt;
&lt;/li&gt;
&lt;li&gt;Configuration &lt;/li&gt;
&lt;li&gt;Integration with private DNS zone: Yes &lt;/li&gt;
&lt;li&gt;Subnet: default subnet in VN1 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298572i3DD2D04F430E6783%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="SignalR Service Configuration"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Go to the network access control blade of ASRS1 and disable the all connections in public network.
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setup the Application Gateway
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create the &lt;a href="https://azure.microsoft.com/services/application-gateway" rel="noopener noreferrer"&gt;Application Gateway&lt;/a&gt; &lt;strong&gt;&lt;em&gt;AG1&lt;/em&gt;&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;In the Basic, use the &lt;strong&gt;&lt;em&gt;VN1&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;gatewaySN&lt;/em&gt;&lt;/strong&gt; to configure the virtual network.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298576iA2B8FC1EA1828A1B%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="Application Gateway - Basic"&gt;
&lt;/li&gt;
&lt;li&gt;In the Frontends, create a new public address.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298575i5B2B6D532C69145E%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="Application Gateway - Frontends"&gt;
&lt;/li&gt;
&lt;li&gt;In the Backends, create a new backend pool signalr for the SignalR Service resource. You need to use the host name of the SignalR Service resource as the Target. 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298574i3E0ADDD849D6A4D2%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="Application Gateway - Backends"&gt;
&lt;/li&gt;
&lt;li&gt;In the Configuration, add a new routing rule signalrrule to route the traffic to SignalR Service. You need to create a new HTTP setting.

&lt;ul&gt;
&lt;li&gt;Listener &lt;/li&gt;
&lt;li&gt;Protocol: HTTP (We use the HTTP frontend protocol on Application Gateway in this blog to simplify the demo and help you get started easier. But in reality, you may need to enable HTTPs and Customer Domain on it with production scenario.)
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298577iDFAF0C0B4C92A1A1%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="Application Gateway - Listener"&gt; &lt;/li&gt;
&lt;li&gt;Backend targets
&lt;/li&gt;
&lt;li&gt;Target type: Backend pool &lt;/li&gt;
&lt;li&gt;Add new HTTP setting

&lt;ul&gt;
&lt;li&gt;Backend protocol: HTTPs &lt;/li&gt;
&lt;li&gt;Use well known CA certificate: Yes &lt;/li&gt;
&lt;li&gt;Override with new host name: Yes &lt;/li&gt;
&lt;li&gt;Host name override: Pick host name from backend target.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298579i2BD58CF013432744%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="Application Gateway - Backend"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Review and create the AG1 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298578i286727C97E7C80C3%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="Application Gateway - Create"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, we already setup the Virtual Network, SignalR Service and Application Gateway. Let’s quick test whether the configuration is correct.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the network access control blade of ASRS1 and set public network to allow server connection only. 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298581iEB693BA66C572E69%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="Configuration Test"&gt;
&lt;/li&gt;
&lt;li&gt;Go to AG1, open health probe, change the health probe path to /api/v1/health 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298582iFAADEBD401C9E9ED%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="Configuration Test"&gt;
&lt;/li&gt;
&lt;li&gt;Go to the Overview blade of AG1, and find out the Frontend public IP address &lt;/li&gt;
&lt;li&gt;Open &lt;a href="http://frontend-public-IP-address" rel="noopener noreferrer"&gt;http://frontend-public-IP-address&lt;/a&gt;, and it should return 403. &lt;/li&gt;
&lt;li&gt;Open &lt;a href="http://frontend-public-IP-address/api/v1/health" rel="noopener noreferrer"&gt;http://frontend-public-IP-address/api/v1/health&lt;/a&gt;, and it should return 200. &lt;/li&gt;
&lt;li&gt;Go back to the network access control blade of ASRS1 and disable the server connection in public network.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Run a Chat Application Locally
&lt;/h2&gt;

&lt;p&gt;Now, the traffic to Azure SignalR is already managed by the Application gateway. The customer could only use the public IP address or custom domain name to access the resource. In this blog, let’s use the &lt;a href="https://github.com/aspnet/AzureSignalR-samples/tree/main/samples/ChatRoom" rel="noopener noreferrer"&gt;chat application&lt;/a&gt; as an example, and start from running it locally.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the github repo &lt;a href="https://github.com/aspnet/AzureSignalR-samples" rel="noopener noreferrer"&gt;https://github.com/aspnet/AzureSignalR-samples&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go to the Keys blade of ASRS1 and get the connection string
&lt;/li&gt;
&lt;li&gt;Go to samples/Chatroom and open the shell &lt;/li&gt;
&lt;li&gt;Set the connection string and run the application locally
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet restore 
dotnet user-secrets set Azure:SignalR:ConnectionString "&amp;lt;connection-string-of-ASR1&amp;gt;;ClientEndpoint=http://&amp;lt; frontend-public-IP-address-of-AG1&amp;gt;" 
dotnet run 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Open &lt;a href="http://localhost:5000" rel="noopener noreferrer"&gt;http://localhost:5000&lt;/a&gt; and view network traces via explorer to see WebSocket connection is established through AG1  
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F298583iF7CDDD3105B8B701%2Fimage-dimensions%2F687x177%3Fv%3Dv2" alt="Run Test"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deploy the Chat Application to Azure
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a Web App &lt;strong&gt;&lt;em&gt;WA1&lt;/em&gt;&lt;/strong&gt;. 

&lt;ul&gt;
&lt;li&gt;Publish: Code &lt;/li&gt;
&lt;li&gt;Runtime stack: .NET Core 3.1 &lt;/li&gt;
&lt;li&gt;Operation System: Windows &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Go to Networking blade and configure the VNET integration.
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;em&gt;VN1&lt;/em&gt;&lt;/strong&gt; and webapp subnet &lt;strong&gt;&lt;em&gt;applicationSN&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Publish the Web App with CLI 

&lt;ul&gt;
&lt;li&gt;Publishe the application and its dependencies to a folder for deployment
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet publish -c Release 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Package the bin\Release\netcoreapp3.1\publish folder as &lt;strong&gt;&lt;em&gt;app.zip&lt;/em&gt;&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Perform deployment using the kudu zip push deployment.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az login  
az account set –subscription &amp;lt;your-subscription-name-used-to-create-WA1&amp;gt; 
az webapp deployment source config-zip -n WA1 -g &amp;lt;resource-group-of-WA1&amp;gt; --src app.zip 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Go to the Configuration blade of &lt;strong&gt;&lt;em&gt;WA1&lt;/em&gt;&lt;/strong&gt;, and add following application setting to set connection string and enable private DNS zone.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Azure__SignalR__ConnectionString=&amp;lt;connection-string-of-ASR1&amp;gt;;ClientEndpoint=http://&amp;lt; frontend-public-IP-address-of-AG1&amp;gt; 
WEBSITE_DNS_SERVER=168.63.129.16 
WEBSITE_VNET_ROUTE_ALL=1  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Go to the TLS/SSL settings blade of &lt;strong&gt;&lt;em&gt;WA1&lt;/em&gt;&lt;/strong&gt;, and turn off the HTTPS Only. To Simplify the demo, we used the HTTP frontend protocol on Application Gateway. Therefore, we need to turn off this option to avoid changing the HTTP URL to HTTPs automatically.
&lt;/li&gt;
&lt;li&gt;Go to the Overview blade and get the URL of &lt;strong&gt;&lt;em&gt;WA1&lt;/em&gt;&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;Open the URL by replacing the https with http, and open network traces to see WebSocket connection is established through &lt;strong&gt;&lt;em&gt;AG1&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Now, you are successful to build a real-time chatroom application with Azure SignalR Service and use Application Gateway to protect your applications and setup end to end secure.  &lt;/p&gt;

&lt;p&gt;If you are trying to build your own application with Azure SignalR and Application Gateway, you could also get more helpful resources from the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-signalr/" rel="noopener noreferrer"&gt;Azure SignalR Service&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/azure/application-gateway" rel="noopener noreferrer"&gt;Azure Application Gateway&lt;/a&gt;. We are looking forward your feedback and ideas to help us become better via &lt;a href="https://feedback.azure.com/forums/915436-azure-signalr-service" rel="noopener noreferrer"&gt;Azure Feedback Forum&lt;/a&gt;! You could also go to &lt;a href="https://techcommunity.microsoft.com/t5/apps-on-azure/bg-p/AppsonAzureBlog" rel="noopener noreferrer"&gt;Tech Community&lt;/a&gt; to learn more blogs about Azure SignalR Service.&lt;/p&gt;

&lt;p&gt;  &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>azure</category>
      <category>azuresignalr</category>
    </item>
    <item>
      <title>Build a real-time whiteboard application with Azure Web PubSub</title>
      <dc:creator>Yan Jin</dc:creator>
      <pubDate>Wed, 07 Jul 2021 09:22:28 +0000</pubDate>
      <link>https://forem.com/azure/build-a-real-time-whiteboard-application-with-azure-web-pubsub-3c4e</link>
      <guid>https://forem.com/azure/build-a-real-time-whiteboard-application-with-azure-web-pubsub-3c4e</guid>
      <description>&lt;p&gt;The COVID-19 pandemic has led to unprecedented measures and is also changing the way we work. In addition to restricting travel and canceling large events, a growing number of companies are encouraging to work remotely. In order to continue working efficiently and creating value under these new circumstances, organizations need to adopt different applications with different scenarios, e.g., web conference, remote collaboration, etc. The real-time whiteboard is one of the tools to help you build remote collaboration and bring your teams together, anytime, anywhere, e.g., running productive and engaging online meetings and workshops, building and developing ideas with distributed teams, explaining complex process and system with visual map or diagram, etc. The Azure Web PubSub (AWPS) which is a fully managed service could help you build the real-time whiteboard application. Let’s learn how to build a whiteboard demo together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s the whiteboard demo?
&lt;/h2&gt;

&lt;p&gt;This whiteboard demo demonstrates how to build a web application for real time collaboration using Azure and other related technologies. The fundamental feature of this application is allowing anyone painting on it and synchronizing the paint to others in real-time. The user could paint with the basic paint tool, touching on mobile devices or uploading images.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F294911i87AB250939F9360A%2Fimage-size%2Flarge%3Fv%3Dv2%26px%3D999" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F294911i87AB250939F9360A%2Fimage-size%2Flarge%3Fv%3Dv2%26px%3D999" alt="Real-time Whiteboard Application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we start digging into details, you can first play with this demo online. Open this &lt;a href="https://awps-demo-whiteboard.azurewebsites.net/" rel="noopener noreferrer"&gt;site&lt;/a&gt; and input your username, then draw anything you like in the whiteboard. Open another browser window you'll see your changes are synchronized in real-time.&lt;/p&gt;

&lt;p&gt;You can also find the source code of this demo &lt;a href="https://github.com/Azure/azure-webpubsub/tree/main/samples/javascript/whiteboard" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Synchronize real-time data between client applications
&lt;/h2&gt;

&lt;p&gt;One of the key features in this whiteboard is its ability to synchronize the drawing between multiple client apps in real-time. This is implemented by using &lt;a href="https://en.wikipedia.org/wiki/WebSocket" rel="noopener noreferrer"&gt;WebSocket&lt;/a&gt; technology, which is commonly used in web applications for bidirectional communication. If you're already familiar with WebSocket and look into the implementation in &lt;a href="https://github.com/Azure/azure-webpubsub/blob/main/samples/javascript/whiteboard/server.js" rel="noopener noreferrer"&gt;server.js&lt;/a&gt;, you'll notice it's very different than a typical WebSocket server. In a typical WebSocket application, server needs to manage all client connections and handle data transfer between clients. So you can imagine in a whiteboard app, server will receive the drawing from one client and broadcast it to all other clients, which will generate huge traffic when everyone is drawing and processing all those data will be a big burden to the server.&lt;/p&gt;

&lt;p&gt;If you look at our whiteboard server, you'll see it's a standard &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;express.js&lt;/a&gt; server application (we don't go through details about how to use express.js here, you can refer to its official docs to learn more). Instead of having code to handle WebSocket connections, it creates a &lt;code&gt;WebPubSubEventHandler&lt;/code&gt; and use it as a middleware in the express app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebPubSubEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hubName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/eventhandler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;handleConnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;onDisconnected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;handleUserEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMiddleware&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using this Web PubSub event handler, we're leveraging &lt;a href="https://azure.microsoft.com/en-us/services/web-pubsub/" rel="noopener noreferrer"&gt;Azure Web PubSub&lt;/a&gt; service to manage the client connections for us.&lt;/p&gt;

&lt;p&gt;In the event handler there're some callbacks like &lt;code&gt;onConnected&lt;/code&gt; and &lt;code&gt;onDisconnected&lt;/code&gt;, which are similar to &lt;code&gt;open&lt;/code&gt; and &lt;code&gt;close&lt;/code&gt; events in WebSocket, but the key difference here is when using Azure Web PubSub service, the connection is connected to the service, your server just gets a notification when this happens but does not need to manage the lifetime of the connection. This is usually challenging in real scenarios where you need to handle things like connection routing and load balancing. In Azure Web PubSub they're all taken care of by the service.&lt;/p&gt;

&lt;p&gt;Also in the server code you'll notice there is no code to pass the data from one client to another, this is purely done at client side. Look at the &lt;a href="https://github.com/Azure/azure-webpubsub/blob/main/samples/javascript/whiteboard/src/websocketclient.js#L40" rel="noopener noreferrer"&gt;client&lt;/a&gt; you'll see code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_webSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sendToGroup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code sends a message to the WebSocket connection but there is no code at server side to handle it! This is because it is processed at service side. Azure Web PubSub can understand message from client (in this case it's asking service to send this message to a group) and send the message to the corresponding clients (which is called publish/subscribe pattern). So you can see by using Azure Web PubSub you can save a lot of server resources (like CPU and network bandwidth) by offloading WebSocket connections to the service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maintain state at server side
&lt;/h2&gt;

&lt;p&gt;Even Azure Web PubSub helps us deliver real-time updates between clients, client still needs to send drawing data to server so it can be saved at server side. So next time when a new user opens the whiteboard, they can see all paintings others draw before.&lt;/p&gt;

&lt;p&gt;This is done by sending an event from client to server. Event is another communication pattern (comparing to publish/subscribe pattern we use for sending real-time updates) in Azure Web PubSub for clients to send data to server.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://github.com/Azure/azure-webpubsub/blob/main/samples/javascript/whiteboard/src/websocketclient.js#L31" rel="noopener noreferrer"&gt;client&lt;/a&gt;, there is code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_webSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code sends an event to server and there is corresponding server &lt;a href="https://github.com/Azure/azure-webpubsub/blob/main/samples/javascript/whiteboard/server.js#L37" rel="noopener noreferrer"&gt;code&lt;/a&gt; to handle it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebPubSubEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hubName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/eventhandler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;handleUserEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;addShape&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;removeShape&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clear&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the code above handles three types of events (when user adds a new shape, removes an existing shape or clears the whiteboard) and save the data to a local &lt;code&gt;diagram&lt;/code&gt; object (for demo purpose, in a real application you should use a persistent storage to store this diagram).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can see there is still data communication between client and server, but comparing to the real-time updates between clients (which happens whenever a user moves their mouse on the screen), this only happens when a user finishes drawing a shape, so the amount of data is much less than the real-time updates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Besides user events, Azure Web PubSub also supports some system events like connected and disconnected so server can know the status of client connections. You can see in the server code, they're used to track the total number of clients online.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use WebSocket API in client
&lt;/h2&gt;

&lt;p&gt;Azure Web PubSub uses &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" rel="noopener noreferrer"&gt;WebSocket API&lt;/a&gt; for its client programming interface. As long as your programming language supports WebSocket, you don't need to install any third-party library. You already see how to send messages through WebSocket in previous sections, but there are a few more things you need to be aware before using it:&lt;/p&gt;

&lt;h3&gt;
  
  
  Authenticate with service
&lt;/h3&gt;

&lt;p&gt;Azure Web PubSub doesn't support anonymous connection, so in order to connect to the service each client needs to authenticate with it using a &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JWT&lt;/a&gt; token. Azure Web PubSub SDK already provides an API to generate the token from connection string. A recommended implementation is to expose a Web API (usually called negotiate) at server to return this token (the API itself can be protected by your own authentication mechanism). In the demo app it's implemented like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/negotiate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;serviceClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAuthenticationToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webpubsub.sendToGroup.draw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the negotiate you can also control the permission of client (like which group it can send message to).&lt;/p&gt;

&lt;h3&gt;
  
  
  Create connection
&lt;/h3&gt;

&lt;p&gt;Create connection is really simple but you need to specify a subprotocol if you want to directly send messages between clients.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/negotiate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json.webpubsub.azure.v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;json.webpubsub.azure.v1&lt;/code&gt; subprotocol, you'll be able to join, leave and publish messages from client (more details can be found &lt;a href="https://azure.github.io/azure-webpubsub/references/pubsub-websocket-subprotocol" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don't specify subprotocol you can still connect, but all messages you send will be treated as events and be sent to server.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Handle reconnect
&lt;/h3&gt;

&lt;p&gt;It's very common that WebSocket connection will drop due to things like network glitches, long time inactivity at client side, etc. So to improve the stability of the client app you should always consider reconnect when it disconnects.&lt;/p&gt;

&lt;p&gt;In Javascript if a WebSocket connection is closed you need to create a new WebSocket object to reconnect, which means for all callbacks you registered on the old object you need to re-register in the new one. In this demo we created a simple WebSocketClient class to wrap the raw WebSocket object so it will automatically reconnect and re-register all callbacks. Check out the &lt;a href="https://github.com/Azure/azure-webpubsub/blob/main/samples/javascript/whiteboard/src/websocketclient.js" rel="noopener noreferrer"&gt;source code&lt;/a&gt; to see how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Now, we already go through the key points to build the real-time whiteboard application with Azure Web PubSub service. If you are looking for more details about this demo, you can refer to the &lt;a href="https://github.com/Azure/azure-webpubsub/tree/main/samples/javascript/whiteboard" rel="noopener noreferrer"&gt;whiteboard application on Github&lt;/a&gt; where the code is hosted, along with information and docs on how to deploy and run it yourself.&lt;/p&gt;

&lt;p&gt;If you are trying to build your first real-time application with Azure Web PubSub, you could also get more helpful resources from the &lt;a href="https://azure.microsoft.com/services/web-pubsub/#documentation" rel="noopener noreferrer"&gt;getting stared contents&lt;/a&gt;. We are looking forward your feedback and ideas to help us become better via &lt;a href="https://feedback.azure.com/forums/934191-azure-web-pubsub-service" rel="noopener noreferrer"&gt;Azure Feedback Forum&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  More Information
&lt;/h2&gt;

&lt;p&gt;This blog is also posted on &lt;a href="https://techcommunity.microsoft.com/t5/apps-on-azure/build-a-real-time-whiteboard-application-with-azure-web-pubsub/ba-p/2522265" rel="noopener noreferrer"&gt;Tech Community&lt;/a&gt; and you could also get more blogs about the Web PubSub and its new features here.&lt;/p&gt;

&lt;p&gt;At last, thanks for &lt;a href="https://techcommunity.microsoft.com/t5/user/viewprofilepage/user-id/692206" rel="noopener noreferrer"&gt;Ken Chen&lt;/a&gt; offering the demo and technical details. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>azure</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Build serverless real-time chat application with Web PubSub and Static Web Apps</title>
      <dc:creator>Yan Jin</dc:creator>
      <pubDate>Tue, 22 Jun 2021 02:53:52 +0000</pubDate>
      <link>https://forem.com/azure/build-serveless-real-time-chat-application-with-web-pubsub-and-static-web-apps-glc</link>
      <guid>https://forem.com/azure/build-serveless-real-time-chat-application-with-web-pubsub-and-static-web-apps-glc</guid>
      <description>&lt;p&gt;With the growth of internet and mobile, building the cross platform real-time chat experience into your application also becomes a very common need, for example patient and doctor chat in healthcare, customer support chat in eCommerce, student and teacher chat in remote education, players chat in eGaming, instant chat for social media or live video stream, and so on. The real-time chat experience offers several values to your application to help your customers success:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instant and efficient communication to faster problem resolution.
&lt;/li&gt;
&lt;li&gt;Collaboration and purposeful conversation to overcome business challenges. &lt;/li&gt;
&lt;li&gt;Smooth built-in experience to improve the customer service and loyalty. &lt;/li&gt;
&lt;li&gt;Cross platform support to empower the customer to discovery easily. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, there are some fundamental and critical needs for an application with build-in real-time chat experience:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time chat experience with users. &lt;/li&gt;
&lt;li&gt;Management of user and group.
&lt;/li&gt;
&lt;li&gt;Notification and popup.
&lt;/li&gt;
&lt;li&gt;AI-enabled, e.g., language moderator, bot, etc.
&lt;/li&gt;
&lt;li&gt;Typing indicator.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it is not easy to build these functionalities into your application from scratch. You may have the issues to achieve the real-time performance, handles hosting, scalability, load balancing and other infrastructure related challenges, adapt with multiple client platforms, etc. Now, the Azure Web PubSub service which is a fully managed service give the opportunity to you to enable the real-time capability to your application with native and serverless WebSockets support. &lt;/p&gt;

&lt;p&gt;Let’s follow with &lt;a href="https://twitter.com/BenCodeGeek" rel="noopener noreferrer"&gt;Ben Coleman&lt;/a&gt; together to build a serverless Chatr web application and learn how does he leverage the advantages of the Azure Web PubSub and Azure Static Web Apps to achieve this easily and quickly. &lt;/p&gt;

&lt;h2&gt;
  
  
  What's the Chatr?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chatr.benco.io/" rel="noopener noreferrer"&gt;Chatr&lt;/a&gt; is a simple real-time, multi-user chat application, highlighting the ease of building applications on top of two of Azure services: &lt;a href="https://azure.microsoft.com/services/web-pubsub/" rel="noopener noreferrer"&gt;Azure Web PubSub&lt;/a&gt; and &lt;a href="https://azure.microsoft.com/services/app-service/static/" rel="noopener noreferrer"&gt;Azure Static Web Apps&lt;/a&gt;. The Chatr application provides many of the features you might expect; a way to sign in and authenticate, group chats, user to user private chats, a global online user list, idle (away from keyboard) detection and more. However it was built to be a way to learn and showcase possibilities rather than a fully fledged and production grade chat system. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F287807iB0F45BC03F96DD74%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F287807iB0F45BC03F96DD74%2Fimage-size%2Fmedium%3Fv%3Dv2%26px%3D400" alt="Chatr Application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chatr consists of four components: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The client or frontend, which users interact with – This is written in JavaScript and uses Vue.js &lt;/li&gt;
&lt;li&gt;The backend service, which provides message processing &amp;amp; event handling, written in Node.js &lt;/li&gt;
&lt;li&gt;A globally available but secure Websockets service – provided by Azure Web PubSub &lt;/li&gt;
&lt;li&gt;Persistence state storage and key value store – provided by Azure Table Storage &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A diagram will help illustrate how these all interact, and some of the main message &amp;amp; data flows. Let’s explore these components in more detail.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F287759i888989074CA0312D%2Fimage-size%2Flarge%3Fv%3Dv2%26px%3D999" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F287759i888989074CA0312D%2Fimage-size%2Flarge%3Fv%3Dv2%26px%3D999" alt="Chatr diagram"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Use Web PubSub to build the scalable backend
&lt;/h2&gt;

&lt;p&gt;The Azure WebPubSub service works hand in hand with the Chatr backend, to provide the core chat functionality. This is done through &lt;a href="https://azure.github.io/azure-webpubsub/references/protocol-cloudevents" rel="noopener noreferrer"&gt;‘event handlers’ within Azure WebPub sub&lt;/a&gt;, these handlers enable an upstream service to receive client side WebSocket messages as “events”. These events are HTTP messages, which the service can then react to. These events supports both a range of built-in system events (e.g. client connecting or disconnecting) but also custom application specific events, in the case of Chatr there are many of these such events, for example “joinChat” or “userEnterIdle” etc. &lt;/p&gt;

&lt;p&gt;The backend uses the service client of the &lt;a href="https://azure.github.io/azure-webpubsub/references/server-sdks/js-server-sdks#service-client-library" rel="noopener noreferrer"&gt;Web PubSub SDK for Node.js&lt;/a&gt;, which can be instantiated easily. Here we are storing configuration details such as the connection string in an Azure Function App Settings, and obtain it them securely through environmental variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { WebPubSubServiceClient } = require('@azure/web-pubsub')
const CONN_STR = process.env.PUBSUB_CONNECTION_STRING 
const HUB = process.env.PUBSUB_HUB 
const serviceClient = new WebPubSubServiceClient(CONN_STR, HUB) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within the Function itself we can handle any event sent to us from clients by binding to HTTP trigger POST requests and processing them as follows. For example, the code below shows how Chatr handles when a user has created a new shared group-chat. When doing so they send an event called “createChat”, when handling this we get the properties we require from both the headers and the HTTP body, (the special 'ce' headers are populated by Azure Web PubSub), then store into state and finally notify all clients about the new chat with an outbound message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ce-eventname&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ce-userid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;createChat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="c1"&gt;// Build custom event payload &lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chatPayload&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt; 
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt; 
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt; 
    &lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 

  &lt;span class="c1"&gt;// ... Update state, removed for brevity ... &lt;/span&gt;

  &lt;span class="c1"&gt;// Send message to all clients with custom JSON payload &lt;/span&gt;
  &lt;span class="c1"&gt;// Will be routed via Azure Web PubSub with WebSocket protocol &lt;/span&gt;
  &lt;span class="nx"&gt;serviceClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
    &lt;span class="na"&gt;chatEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chatCreated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chatPayload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build frontend with extensive platform and host easily with Static Web Apps
&lt;/h2&gt;

&lt;p&gt;The Chatr frontend consists of a JavaScript static app or SPA (single page application) built on the Vue.js framework, this is hosted using the Azure Static Web App service as a set of HTML and JS files. This Azure service aside from just hosting static content, also provides Chatr a means to sign in and authenticate users and also a way to host the backend Azure Function service. The frontend establishes a secure connection to Azure Web PubSub using WebSockets, no SDK or client libraries are required making it quick easy to use. Let's walk through the frontend together. &lt;/p&gt;

&lt;h3&gt;
  
  
  Setup connection between application and backend service
&lt;/h3&gt;

&lt;p&gt;The clients first request a way to access to Azure Web PubSub by calling a REST endpoint on our backend which in turn obtains a client access URL (which includes an access token) this is done using the same serviceClient described above, as this is done server side it provides a way to restrict access and secure the application. In the case of Chatr all users are permitted to request an access URL. The userId in the code below has been &lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/authentication-authorization" rel="noopener noreferrer"&gt;fetched previously through a call to Azure Static WebApps&lt;/a&gt;, for the purposes of Azure Web PubSub. It’s simply a string and has no special meaning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Get URL &amp;amp; token to connect to Azure Web Pubsub &lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/getToken?userId=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 

&lt;span class="c1"&gt;// Now connect to Azure Web PubSub using the URL we obtained &lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json.webpubsub.azure.v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We only use standard modern JavaScript APIs like fetch and WebSocket this means the Chatr frontend can be deployed without any bundling or WebPack stage. Also note how we use the ‘json.webpubsub.azure.v1' subprotocol when establishing the connection, this &lt;a href="https://azure.github.io/azure-webpubsub/references/pubsub-websocket-subprotocol.html" rel="noopener noreferrer"&gt;extension to plain WebSockets provides a range of additional capabilities&lt;/a&gt; which are used by Chatr such as; client to client messaging (without a round trip to the server), a means to join send messages to groups (which is how Chatr provides group chats) and also a way to send custom events which are routed to the service as described above. &lt;/p&gt;

&lt;h3&gt;
  
  
  Send custom event or message
&lt;/h3&gt;

&lt;p&gt;Sending a custom event from the client is very simple, for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;createChat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chatName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chatId&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chat messages between users are sent a very similar way, except leveraging the 'sendToGroup' message type. Rather than plain text strings (which are also supported) we enrich the messages we send with meta data such as the userId of who sent the message and send a JSON payload. It’s important to note these messages are not relayed by the Chatr backend we described above, they are handled entirely by the Azure Web PubSub service without any backend or server code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sendToGroup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chatId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fromUserId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We’ve just scratched the surface of what the Chatr sample app does, and we’ve not covered details such as how state is stored using Azure Tables or how the authentication wrappers of Azure Static WebApps are used.  However I hope what we have shown illustrates some of the power and flexibility of Azure Web PubSub. If you are looking for more details about this application, you can refer to the &lt;a href="https://github.com/benc-uk/chatr" rel="noopener noreferrer"&gt;Chatr repo on GitHub&lt;/a&gt; where the code is hosted, along with information and docs on how to deploy it to Azure and run it yourself. &lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;If you are trying to build your first real-time application with Azure Web PubSub, you could also get more helpful resources from the &lt;a href="https://azure.microsoft.com/services/web-pubsub/#documentation" rel="noopener noreferrer"&gt;getting stated contents&lt;/a&gt;. We are looking forward your feedback and ideas to help us become better via &lt;a href="https://feedback.azure.com/forums/934191-azure-web-pubsub-service" rel="noopener noreferrer"&gt;Azure Feedback Forum&lt;/a&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  More Information
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;This blog is also posted on &lt;a href="https://techcommunity.microsoft.com/t5/apps-on-azure/build-serveless-real-time-chat-application-with-web-pubsub-and/ba-p/2433211" rel="noopener noreferrer"&gt;Tech Community&lt;/a&gt; and you could also get more blogs about the Web PubSub and its new features here.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>serverless</category>
      <category>azure</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
