Real Time Communication to Cross Platform Devices using Azure SignalR Service

In this article, i will discuss about how to do real time communication between cross platform devices such as .net core web app runs in Azure, xamarin based android app and Full .Net Framework based Windows Forms app running in Windows Operating System by sending and receiving data using Azure SignalR Service. In this two part of article series, i will create a tool called MagicPaste which will transfer the text content from one device to another in real time.

This article provides an overview of architecture of Magic Paste tool and how to setup the SignalR Service in Azure SignalR Portal. It also provides the overview of how to develop SignalR Client Web , Android and Windows Forms App to communicate each other in real time using Azure SignalR Service.

Architecture

Demo

Setting up Azure SignalR Service

Microsoft recently released the preview version Azure SignalR service which is a fully-managed service that allows developers to focus on building real-time web experiences without worrying about capacity provisioning, reliable connections, scaling, encryption or authentication. In this example, I setup the Azure SignalR Service with the Free Tier which allows the maximum of single unit with 100 connections. This would be suffcient for this demo.

Steps

  • Login to Azure Portal and Click Create a Resource and Search for SignalR Service in Market Place and click the Create button.

  • Enter the resource name, Select the Subscription , Resource Group and the Free Pricing Tier and then click the Create Button.

  • We have now created the Azure SignalR Service succesfully. Navigate to the dashboard page of SignalR Service that we created just now and copy the EndPoint URL with the accesskeys under the Keys Section. User Access Keys are used to authenticate SignalR clients when making request to Azure SignalR Service. It is very important to keep these keys securely. During the development time, you can store the keys in usersecrets.json file so that it will not get checked in into source control by accident. When you deploy the SignalR Web Client App, you can deploy the keys into Azure Key Vault or AppSettings in Azure Web App Service.

Client Apps

We will develop the SignalR client applications to connect to Azure SignalR Service to do real time communication between cross platform devices. We are going to develop the following applications.

  • Net Core We App to send and receive the data from the browser.
  • Net Framework (v4.6.1) based windows forms application that running in system tray with the global hot key registered (CTRL + SHIFT + C) to push the clipboard content to other devices whenever the hotkey is pressed.
  • Xamarin based Android App to receive the data from SignalR Hub in Local Notification Window.

Web App SignalR Client App

This is an Asp.net Core Web Application with layout defined using bootstrap library. In the landing page, we will be adding DIV container to show all the incoming messages from SignalR Hub and in the bottom of the page, we will place the text box and button to publish the text message to other clients. We will use the SignalR Javascript Client library to connect to SignalR Hub.

Steps

  • Launch the Visual Studio and Create a New Project (.Net Core -> Asp.net Core Web Application) . You must have the latest .Net Core SDK (2.1) installed on your machine.

  • Install the Microsoft.Azure.SignalR Nuget Package for your project.

  • By default, the Microsoft.AspNetCore.SignalR package containing its server libraries as part of its ASP.NET Core Web Application template. However, the JavaScript client library for SignalR must be installed using npm. Use the following commands from Node Package Manager Console to install it and copy the signalr.js file from node_modules\@aspnet\signalr\dist\browser to wwwroot\lib\signalr\signalr.js. (Create a SignalR Folder under Lib Directory)
npm init -y 
npm install @aspnet/signalr
  • We will create a new hub called MagicPasteHub that internally connects to Azure Service. Right click on the Project in Solution Explorer and Create a New Folder called Hub and then add a new file called MagicPasteHub.cs and paste the following code.

    public class MagicPasteHub : Hub
    {
    public async void SendData(string data)
    {
    await Clients.All.SendAsync("ReceiveData", data);
    }
    }
  • In the Startup.cs, add the following code in ConfigureServices method. SignalREndPoint Key will hold the Azure Endpoint Value. During Development time, you can store the Azure Endpoint Values in UserSecrets.json. The method AddAzureSignalR will establish the link between Web App and Azure SignalR library using the EndPoint URL.

    services.AddSignalR().AddAzureSignalR(
    Configuration["AppSettings:SignalREndPoint"])
    .AddHubOptions<magicpastehub>(a => a.EnableDetailedErrors = true);
  • Add the following code in Configure Method to map the AzureSignalRService with MagicPasteHub Route URL

    app.UseAzureSignalR(routes =>
    {
    routes.MapHub<magicpastehub>("/MagicPaste");
    });
  • In the site.js, add the following code to setup the signalR client to connect to hub and wire up the button click event to send the message and wire up the ReceiveData event to append the incoming data into DIV container.

    const connection = new signalR.HubConnectionBuilder()
    .withUrl("/MagicPaste")
    .build();

    connection.start();

    $("#btnPublish").click(function () {
    var msg = $("#inputData").val();
    if (msg.length > 0) {
    connection.invoke("SendData", msg).catch(err => console.error(err.toString()));
    $("#inputData").val('');
    }
    });

    connection.on("ReceiveData", (msg) => {
    $("#messagesList").append($("
    <li class="list-group-item list-group-item-info">").html(msg));
    });

    $('#inputData').keypress(function (event) {
    if (event.keyCode == 13) {
    $('#btnPublish').click();
    }
    });

The entire source of web client app is uploaded here in github.

Windows Forms App SignalR Client

This is a full .net framework based windows forms app that will be running in the system tray with the registered global hotkey CTRL + SHIFT + C. Whenever hot key is pressed anywhere in the desktop, app will check and publish the content of the clipboard to other clients. I used NHotKey open source library for registering the hotkey in Windows Forms.

Steps

  • Launch the Visual Studio and Click on File -> New Project and Select Windows Forms Application under Windows Desktop Section.
  • After creating the application, Install the NuGet Package of Microsoft.AspNetCore.SignalR.Client Library for the signalr support..

  • In the MainForm.cs add the following code. The code below will register the global hotkey (CTRL + SHIFT + C) and also initialize the connection with SignalR hub
    private void MainForm_Load(object sender, EventArgs e)  
    {
    HotkeyManager.Current.AddOrReplace("OnHotKeyPressed", Keys.Control | Keys.Shift | Keys.C, true, OnHotKeyPressed);
    client.Initialize();

    this.WindowState = FormWindowState.Minimized;
    MinimizeToTray();
    this.ShowInTaskbar = false;
    }

Add the new File called AzureSignalRClient.cs. This is the wrapper class to to put all the Azure SignalR Client related code.

public class AzureSignalRClient
{
private MainForm mainForm;
public AzureSignalRClient(MainForm _mainForm)
{
mainForm = _mainForm;
}
private HubConnection connection;
TaskScheduler uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
public async void Initialize()
{
connection = new HubConnectionBuilder()
.WithUrl("https://magicpaste.azurewebsites.net/MagicPaste")
.Build();

connection.On<string>("ReceiveData", (msg) =>
{
mainForm.Invoke((Action)(() =>
mainForm.txtIncomingData.Text = msg
));
});

try
{
await connection.StartAsync();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}

public async void SendData(string msg)
{
await connection.InvokeAsync("SendData", msg);
}

public async void Close()
{
await connection.StopAsync();
}
}
  • When the form gets loaded, it initialize the connection to SignalRHub and whenever the hot key is pressed, it will send the data to Azure Hub.

Xamarin SignalR Client Android App

This is a xamarin based android app which connects to SignalR hub to receive the messages and show as notification to the user and then when the user is clicking the notification, it opens the application with the list of content shared so far in the list view.

Steps

  • Launch the visual studio and select the Android -> Android App (Xamarin) from the Menu.

  • From the Solution Explorer, Select Manage NuGet Packages and Select Microsoft.AspNetCore.SignalR.Client Library and Install it.

  • In MainActivity.cs, Initialize the SignalR Connection as part of OnCreate Method and wire up the SignalR Receive Data event to send the Notification with the received message. I used SharedPreferences to store all the incoming data as Json and display it in the List Activity.
    public class MainActivity : ListActivity
    {
    protected override void OnCreate(Bundle savedInstanceState)
    {
    base.OnCreate(savedInstanceState);

    ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, GetItemsFromPreferences());

    InitializeSignalRClient();
    }

    private async void InitializeSignalRClient()
    {
    var connection = new HubConnectionBuilder()
    .WithUrl("https://magicpaste.azurewebsites.net/MagicPaste")
    .Build();

    connection.On<string>("ReceiveData", (msg) =>
    {
    SaveData(msg);
    ShowNotification(msg);
    });

    try
    {
    await connection.StartAsync();
    }
    catch (Exception e)
    {
    Log.Error("MagicPaste", e.Message);
    }
    }

    private List<string> GetItemsFromPreferences()
    {
    // get shared preferences
    ISharedPreferences pref = Application.Context.GetSharedPreferences("MagicPaste", FileCreationMode.Private);

    // read exisiting value
    var itemsFromSP = pref.GetString("Items", null);

    // if preferences return null, initialize listOfCustomers
    if (itemsFromSP == null)
    return new List<string>();

    var items = JsonConvert.DeserializeObject<List<string>>(itemsFromSP);

    if (items == null)
    return new List<string>();

    return items;
    }

    private void SaveData(string msg)
    {
    // get shared preferences
    ISharedPreferences pref = Application.Context.GetSharedPreferences("MagicPaste", FileCreationMode.Private);

    // read exisiting value
    var itemsFromSP = pref.GetString("Items", null);
    IList<string> items;
    // if preferences return null, initialize listOfCustomers
    if (itemsFromSP == null)
    items = new List<string>();
    else
    items = JsonConvert.DeserializeObject<List<string>>(itemsFromSP);

    // add your object to list of customers
    items.Add(msg);

    // convert the list to json
    var itemsAsJson = JsonConvert.SerializeObject(items);

    ISharedPreferencesEditor editor = pref.Edit();

    // set the value to Customers key
    editor.PutString("Items", itemsAsJson);

    // commit the changes
    editor.Commit();
    }

    private void ShowNotification(string msg)
    {
    Intent intent = new Intent(this, typeof(MainActivity));

    // Create a PendingIntent; we're only using one PendingIntent (ID = 0):
    const int pendingIntentId = 0;
    PendingIntent pendingIntent =
    PendingIntent.GetActivity(this, pendingIntentId, intent, PendingIntentFlags.CancelCurrent);

    Notification.Builder builder = new Notification.Builder(this)
    .SetContentIntent(pendingIntent)
    .SetContentTitle("MagicPaste")
    .SetContentText(msg)
    .SetAutoCancel(true)
    .SetSmallIcon(Resource.Drawable.notification_tile_bg);

    // Build the notification:
    Notification notification = builder.Build();

    // Get the notification manager:
    NotificationManager notificationManager = GetSystemService(NotificationService) as NotificationManager;
    // Publish the notification:
    const int notificationId = 0;
    notificationManager.Notify(notificationId, notification);
    }
    }

Conclusion

SignalR services are mainly used for Apps with Real-Time technologies with high-frequency data flows and large quantities of concurrent connections between the client and server. Now with Azure SignalR Service, it allows you to use ASP.NET Core SignalR to build real-time experiences such as chat, live dashboards, colloboration editor and more, all without worrying about capacity provisioning, scaling, or persistent connections. This article explains the basic idea of how to use Azure SignalR Service However, for the real world implementation, we need to look at the fact of application performance and battery optimization for mobile apps before implementing SignalR services.

I have uploaded the entire source code of Web, Android and WinForms in my github repository.

Happy Coding.