Real Time Cricket Score Chrome Extension Using Azure Functions And SignalR

Introduction

In this article, I will discuss how to show real-time cricket score notifications from a Chrome extension using serverless Azure Functions and Azure SignalR. I have used cricapi.com free API service to get the live cricket score updates. The purpose of this article is to show the power of serverless architecture using Azure functions and broadcasting to connected clients in real-time using Azure SignalR. The demo source code I attached to this article is for the personal educational purposes only and not production use.  

Register Cricket Services API

As a first step, to consume the API Service from 
cricapi.com, register the account with the details to get the API Key. They allow 100 free hits per day for the testing purposes. 
 
Register Cricket Services API
 
Creating Azure SignalR Service

Log into your Azure Portal (https://portal.azure.com/) and create a new resource of type SignalR Service. After the service is created, copy the connection string from the Keys section. 
 
Azure SignalR Service 

Creating Azure Function App

Prerequisites
  • Visual Studio 2017 Latest Version
  • Azure Portal Account
Launch the Visual Studio and Create a New Azure Function Project.
 
Azure Function App 

Select the Azure Function v2 Preview and the HTTP trigger template.
 
Http trigger template 
 
For this demo, we will be creating two Azure functions.
  • NegotiateFunction (HttpTrigger)

    • This function will get the JWT token for the client so that SignalR client can connect to Azure Signalr Service Hub.

  • BroadcastFunction (TimerTrigger)

    • This function runs every 1 min (configurable) and calls the CricAPI Service to get the latest score for defined match id and broadcasts it to all connected clients.
In order to use Azure SignalR Service in Azure Functions, I have used Anthony Chu's “AzureAdvocates.WebJobs.Extensions.SignalRService” library.
 
Azure SignalR Service 

NegotiateFuntion.cs
 
  1. public static class NegotiateFunction  
  2.     {  
  3.         [FunctionName("negotiate")]  
  4.         public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get""post", Route = null)]HttpRequest req,  
  5.             [SignalRConnectionInfo(HubName = "broadcasthub")]SignalRConnectionInfo info, ILogger log)  
  6.         {  
  7.             return info != null  
  8.                 ? (ActionResult)new OkObjectResult(info)  
  9.                 : new NotFoundObjectResult("Failed to load SignalR Info.");  
  10.         }  
  11.     }  
BroadCastFunction.cs 
  1. public static class BroadcastFunction  
  2.     {  
  3.         private static HttpClient httpClient = new HttpClient();  
  4.   
  5.         [FunctionName("broadcast")]  
  6.         public static async void Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer,  
  7.             [SignalR(HubName = "broadcasthub")]IAsyncCollector<SignalRMessage> signalRMessages, ILogger log)  
  8.         {  
  9.             httpClient.DefaultRequestHeaders.Accept.Clear();  
  10.             httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
  11.   
  12.             //TODO: API key should be stored in Azure Key Vault .  
  13.             //For Demo purpose, i hard coded the value here.  
  14.             var values = new Dictionary<stringstring>  
  15.             {  
  16.                 //Hard coded Cricket Match Unique ID. You can change the Match id based on ongoing matchers  
  17.               {"apikey""_API_KEY_HERE"},{"unique_id""1119553"}  
  18.             };  
  19.   
  20.             using (var response = httpClient.PostAsJsonAsync(new Uri("http://cricapi.com/api/cricketScore/"), values).Result)  
  21.             {  
  22.                 var resultObj = response.Content.ReadAsStringAsync().Result;  
  23.                 dynamic result = JsonConvert.DeserializeObject(resultObj);  
  24.   
  25.   
  26.                 await signalRMessages.AddAsync(new SignalRMessage()  
  27.                 {  
  28.                     Target = "broadcastData",  
  29.                     Arguments = new object[] { result.score }  
  30.                 });  
  31.             }  
  32.         }  
  33.     }  
We have to create Appsettings Key called AzureSignalRConnectionString in order to connect to Azure SignalR Service from our Azure Functions. We will have to add the settings in local.settings.json for local testing and add it into Application Settings in Azure after we deploy it. 

local.settings.json
  1. {  
  2.   "IsEncrypted": false,  
  3.   "Values": {  
  4.     "AzureWebJobsStorage": "UseDevelopmentStorage=true",  
  5.     "AzureWebJobsDashboard": "UseDevelopmentStorage=true",  
  6.     "FUNCTIONS_WORKER_RUNTIME": "dotnet",  
  7.     "AzureSignalRConnectionString": "Endpoint=https://magicpaste.service.signalr.net;AccessKey="  
  8.   },  
  9.   "Host": {  
  10.     "LocalHttpPort": 7071,  
  11.     "CORS": "*"  
  12.   }  
  13. }  
We are now done with the coding for the Azure functions, we can start testing it locally first before deploying into Azure Portal. In the local.settings.json, we have defined the localhttpport 7071 and allowed cross domains request by putting CORS : *

Run the Application by pressing F5 which will create the host and deploy the functions in localhost.
 
Register Cricket Services API 

As you see above, Azure Functions are now hosted in local, we can run the negotiate function using the following URL which will return the JWT Token to connect to SignalR Service.
 
SignalR Service
Now, that it worked in localhost, we can deploy the Azure Functions into Azure Portal.
 
Publishing Azure Function App

In Visual Studio, Right click on the solution and Select the Publish option from the Menu.
 
Azure Function App 
 
Check the Run from ZIP checkbox and click the Publish button.
 
ZIP checkbox 
 
Click on the Create button to create the Azure hosting plan storage account under your Azure subscription. After the account is created,  clicking the publish button any time will ship the files into the portal and deploy the Azure Functions.
 
Azure Functions 
 
You can log in to Azure Portal to check the deployed Azure Functions.
 
Azure Functions 
 
We also need to add the AzureSignalRConnectionString key in Application Settings.

AzureSignalRConnectionString  
 
We have completed publishing Azure Functions in the Portal. Let us now create a Chrome extension signalr client to receive the cricket score in real time. The timer trigger broadcast function will run every minute and push the cricket score to all connected clients.

Creating Chrome Extension

SignalRClient.js
  1. const apiBaseUrl = 'https://azurefunctionscricketscore20180911095957.azurewebsites.net';  
  2. const hubName = 'broadcasthub';  
  3.   
  4. getConnectionInfo().then(info => {  
  5.   const options = {  
  6.     accessTokenFactory: () => info.accessKey  
  7.     };  
  8.     
  9.   const connection = new signalR.HubConnectionBuilder()  
  10.     .withUrl(info.endpoint, options)  
  11.     .configureLogging(signalR.LogLevel.Information)  
  12.     .build();  
  13.   
  14.     connection.on('broadcastData', (message) => {  
  15.         new Notification(message, {  
  16.             icon: '48.png',  
  17.             body: message  
  18.           });     
  19.   });  
  20.   connection.onclose(() => console.log('disconnected'));  
  21.   
  22.   console.log('connecting...');  
  23.   connection.start()  
  24.     .then(() => console.log('connected!'))  
  25.     .catch(console.error);  
  26. }).catch(alert);  
  27.   
  28. function getConnectionInfo() {  
  29.   return axios.post(`${apiBaseUrl}/api/negotiate`)  
  30.     .then(resp => resp.data);  
  31. }  
Manifest.json

In the manifest.json, we defined the list of scripts to load (axios, signalr, and signal client). 
  1. {  
  2.   "name""Real Time Cricket Score Demo",  
  3.   "version""1.0",  
  4.   "description":  
  5.     "Real time Cricket Score Update from Serverless Azure Functions pop up on the desktop.",  
  6.   "icons": {"16""16.png""48""48.png""128""128.png"},  
  7.   "permissions": [  
  8.     "background",  
  9.     "tabs",  
  10.     "notifications",  
  11.     "http://*/*",  
  12.     "https://*/*"  
  13.   ],  
  14.   "background": {   
  15.     "persistent"true,  
  16.     "scripts": ["axios.min.js","signalr.js","signalrclient.js"] },  
  17.   "manifest_version": 2,  
  18.   
  19.   "web_accessible_resources": [  
  20.     "48.png"  
  21.   ]  
  22. }  
To install the Chrome extension in your local machine, launch Chrome and open the extensions from the menu. Click the load unpacked extension and select the folder in which the Chrome extension is placed. 
 
load unpacked extension 
 
After the extension is installed, a broadcast Azure function will execute based on the schedule and broadcast the latest score to the newly connected client as below.

broadcast azure function 
 
Conclusion

With a few lines of code, we have created the serverless Azure functions, which will fetch the data from the API endpoint and broadcast the messages to all connected clients in real time using Azure SignalR. In this article, I have hard coded the API key in the program but ideally, it should be stored in Azure Key Vault and read it from there. I hope this article helps you get started with Azure Functions. I have uploaded the entire source code in my github repository.

Happy Coding!