Tuesday, September 17, 2019

Adding Azure SignalR Service to CosmosDB Change Feed


     Registering and Binding different Azure services with Azure Cosmos DB Change Feed can be a challenge. Especially, if the service you are trying to use does not have an input or output trigger template. Azure SignalR is one of these services. SignalR can do magical things for your solution, but it can be a challenge to register it and use it in your solution. In this post, I will guide you to add Azure SignalR Service to your Cosmos DB Change Feed feature.

     SignalR allows server code to send asynchronous notifications to client-side web applications. By using it, Azure Functions can send real-time messages to your web applications. Prices can get change whenever data changes in database. Notices can be sent if user needs to be notified. Numbers in dashboard can change dynamically when data changes in Cosmos DB. You can do all those with Azure Cosmos DB + Azure Functions and SignalR. This combination works like David Copperfield magic.

    Let's say we own a Home Security Company; we sell security units to our customers with bunch of security sensors. Sensors connect to the main unit at a home and whenever a sensor detects something, Main unit sends a message to Azure Cosmos DB. We have Change Feed configured for CosmosDB to detect and do something whenever we receive a signal from any customer. You can find how to do that in my earlier post.

     In this post, I want to add Azure SignalR Service to this solution. I want to monitor Azure Functions by using SignalR. Whenever there will be a new signal, I want to display it on a web application which is used by employees.

    First, we need to create a Azure SignalR Service. Search for SignalR Service in Azure Portal and click on Create New.  Select Free for Pricing tier and keep Service Mode in Default. That's it to create an Azure SignalR Service. Click on Review Create and wait until it starts.



     We have Azure SignalR Service running, we can add this service to Azure Function now. First, you need to add SignalR Nuget packages to your function so you can call SignalR functions. Follow my older post about how to register Nuget packages to Azure functions. You must complete this part first. Without registering required Nuget packages, you cannot call SignalR Services.

     SignalR will be an output binding, there is no template for SignalR Service as output binding yet. We need to setup manually. Click on Integrate button under your Azure Function then click on Advanced Editor.



     Now you should see the function.json file. This file has all the binding information. You should have all the CosmosDB connections when you open it first time. Don't touch any of them, we need to add Nuget settings here. We need to add the following information into this file.


 "type": "signalR", 
 "name": "signalRMessages", 
 "hubName": "messages", 
 "direction": "out" 
 }

     type : It tells to Azure Function that this is a SignalR Service.
     name: This will display in Outputs drop down.
     hubName: This is the channel Azure function will use to send messages. SignalR works like a radio station, clients (web applications) need to be in the right channel to listen stations. In this case we are specifying which frequency we are going to use to send messages. You can name hubName whatever you like. You want to be sure that, you use the same name to listen these messages from your web application.
    direction: This can be input or output. In our case, it is out

     After you add this information, function.json should look like the following. Your CosmosDB Trigger information should be different that mine.



     We are ready to write some code to send messages to Azure SignalR Service. First, you must have a function named negotiate in your Azure Function. This function is required by SignalR, and it used to handshake with Azure SignalR Service. Only thing, you need to change in the following function is the HubName. Type your hubName there and add it to your Azure Function which receives messages from Azure CosmosDB

[FunctionName("negotiate")] 
public static SignalRConnectionInfo GetSignalRInfo([HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req, [SignalRConnectionInfo(HubName="messages")] SignalRConnectionInfo connectionInfo)

 return connectionInfo; 



    Next, we need to add code which will be responsible to send messages to Azure SignalR Service.I am going to call this function sensorfired. We need to add SignalR parameter to the main function too.

[FunctionName("sensorfired")]
public static async Task Run(IReadOnlyList<Document> input,[SignalR(HubName="messages")]IAsyncCollector<SignalRMessage> signalRMessages, ILogger log)
{
if (input != null && input.Count > 0)
{
foreach(Document document in input)
{
Signal item = (dynamic)document;
await signalRMessages.AddAsync(new SignalRMessage{
Target = "sensorfired",
Arguments = new[] {item.SensorCode}
});
}
}
}


     Don't forget to use your hubName in this code, await signalRMessages.AddAsync is the line that sends a signal to Azure SignalR Services. Target is the name of the function which will run in client side when it receives this message. Arguments can be anything, this is the message you are passing to client side. You can check Azure SignalR usage charts to see the trafic. You should be able to see incoming messages from Azure Function after you have some changes in your CosmosDB.


     I will show you how to use Azure SignalR Service in your web application in my next post. So far, we have a system that detects the changes in Azure CosmosDB. For each change, it sends a signal to Azure SignalR Service. Next will be creating a web application that uses Azure SignalR Service to display these messages.

2 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hi Hasan,
    Thanks for deep dive into technical aspects on the SignalR binding to Azure Function. I feel its a best in class among all articles , blogs and Videos across internet.
    Your post helped me to understand SignalR and Azure Function.

    ReplyDelete