Sunday, 2 September 2012

Modifying and Monitoring price of Gold and Silver using SignalR


In my first post, I showed you how to get started with SignalR by creating a simple Hello World type of application. In this post, we will create a simple market application using SignalR. The market deals with prices of gold and silver. We will have two HTML pages in this application. Out of which, one is an admin page; we can modify the prices using this page. The other page is a client page; which displays the current prices of gold and silver with an indicator that shows whether the price went up or down.

Setting up the environment

Start Visual Studio 2010 (or 2012) and choose File -> New -> Project. From the dialog, choose the Empty Web Application template. Make sure that the target version of the project is .NET framework 4 or later. Name the application and hit OK.

Add the dependencies of SignalR using NuGet. Right click on References in the Solution Explorer and choose Manage NuGet Packages or Add Library Package Reference, depending on the version of NuGet installed on your system. Search for SignalR and click on the install button.

Add a folder to the project and change its name to Images. Download an image of a gold biscuit and an image of a silver biscuit and add them to this folder. If you don't want to search, you may grab them from the source code (download link is provided at the end of this post). We will display these images on the pages.

Creating hub class

Add a class to the project and name it GSPriceHub (Gold and Silver price hub). Extend this class from Microsoft.AspNet.SignalR.Hub class, the base class to create an hub in SignalR.

A JavaScript proxy of this class will be created in the /signalr/hubs script that gets generated automatically. By default, name of the proxy object for GSPriceHub class will be gSPriceHub. But, we can change this name using the HubName attribute. I am renaming the hub as priceHub using this attribute as follows:

[HubName("priceHub")]
public class GSPriceHub : Hub
{
}

Implementation of the hub class is straight forward. The hub will have an array of length 2 to store the prices. It will have methods to send initial and modified values of the prices.

    [HubName("priceHub")]
    public class GSPriceHub : Hub
    {
        double[] prices = new double[2];

        public void InitializePrices()
        {
            prices[0] = 28596;
            prices[1] = 59365;
        }

        public void ModifyPrices(double[] modifiedPrices)
        {
            prices = modifiedPrices;
            Clients.All.PopulatePrices(prices);
        }

        public void GetPrices()
        {
            InitializePrices();
            Clients.All.PopulatePrices(prices);
        }
    }

We need to define the PopulatePrices method on the client. Admin page will call the ModifyPrices method. Let's indicate the admin once the execution of ModifyPrices method finishes. We can do this using the property Caller defined in the Hub class. We need to add another statement to the ModifyPrices method to call a client script defined in the admin page. The modified method is as follows:

        public void ModifyPrices(double[] modifiedPrices)
        {
            prices = modifiedPrices;
            Clients.All.PopulatePrices(prices);
            Clients.Caller.PricesModified();
        }

The Pricesmodified method has to be defined in the admin page.


Creating the Admin page
Add an HTML page to the application. Right click on the application and choose Add -> New Item and choose HTML page from the dialog. Add the following HTML markup to the body:

<strong style="font-size: x-large">Prices of Gold and Silver in India</strong> <br />
    <form>
    <table border="0" cellpadding="0" cellspacing="0">
        <tr>
            <td> Gold </td>
            <td> &nbsp; </td>
            <td> <img src="Images/gold.jpg" alt="Gold" height="100" width="100" /> </td>
            <td> &nbsp; </td>
            <td> <input type="text" id="goldPrice" /> </td>
        </tr>
        <tr>  
            <td> &nbsp; </td>
            <td> &nbsp; </td>
            <td> &nbsp; </td>

            <td> &nbsp; </td>
        </tr>
        <tr>
            <td> Silver </td>
            <td> &nbsp; </td>
            <td> <img src="Images/silver.jpg" alt="Gold" height="100" width="100" /> </td>
            <td> &nbsp; </td>
            <td> <input type="text" id="silverPrice" /> </td>
        </tr>
    </table>
    <input type="button" id="modifyPrices" value="Modify Prices" />
    </form>

Add the references of jQuery core library, SignalR jQuery library and reference of the SignalR's dynamic script(/signalr/hubs) to this page. Let's make this page functional by adding some JavaScript. As first step, let's get the references of the input controls and the proxy object.

$(function () {
    var goldPriceTextBox = $("#goldPrice");
    var silverPriceTextBox = $("#silverPrice");
    var modifyPricesButton = $("#modifyPrices");
    var proxy = $.connection.priceHub;
}

Let's display initial prices of gold and silver on the page load. To do this, we need to invoke the GetPrices method defined in the hub class. We can invoke this method once we establish a connection to the hub, which we do by calling $.connection.hub.start() function. We cannot call the server methods unless the start function finished execution. I discussed about different ways to execute a callback function after execution of the start function in my previous post. Add the following code to call the GetPrices method after execution of the start function and display these values on the page:
$.connection.hub.start(function () {
    proxy.server.getPrices();
});

proxy.client.populatePrices = function (prices) {
    goldPriceTextBox.val(prices[0]);
    silverPriceTextBox.val(prices[1]);
};

When user changes the price values and clicks on the Modify Prices button, we have to call the ModifyPrices method defined in the hub. To make the change visible to the user, let's disable the button till the execution completes. Following script achieves this:

modifyPricesButton.click(function () {
    var goldPrice = goldPriceTextBox.val();
    var silverPrice = silverPriceTextBox.val();
    var modifiedPrices = new Array();

    modifiedPrices[0] = goldPrice;
    modifiedPrices[1] = silverPrice;

    modifyPricesButton.attr("disabled", "disabled");
    proxy.server.modifyPrices(modifiedPrices);
});

proxy.client.pricesModified = function () {
    window.setTimeout(function () {
    modifyPricesButton.removeAttr("disabled")
    }, 2000);
};

Execution of the hub function finishes very fast. It is almost impossible to view the state of button changing to disabled and back to enabled. To make it visible, I paused the execution for 2 seconds by calling the window.setTimeout function.


Creating the Client page
Add another HTML page to the application. The client page has a similar view as that of the admin. The only difference is, we have span fields instead of the text input fields. Following is the markup to be placed in the body of the client page:
<strong style="font-size: x-large">Prices of Gold and Silver in India</strong>
    <br />
    <table border="0" cellpadding="0" cellspacing="0">
        <tr>
            <td> Gold (per 10g) </td>
            <td> &nbsp; </td>
            <td> <img src="Images/gold.jpg" alt="Gold" height="100" width="100" /> </td>
            <td> &nbsp; </td>
            <td> <span id="goldPrice" /> </td>
        </tr>
        <tr>
            <td> &nbsp; </td>
            <td> &nbsp; </td>
            <td> &nbsp; </td>
            <td> &nbsp; </td>
        </tr>
        <tr>
            <td> Silver (per 1kg) </td>
            <td> &nbsp; </td>
            <td> <img src="Images/silver.jpg" alt="Gold" height="100" width="100" /> </td>
            <td> &nbsp; </td>
            <td> <span id="silverPrice" /> </td>
        </tr>
    </table>

Add the references of jQuery core library, SignalR jQuery library and reference of the SignalR's dynamic script(/signalr/hubs) to this page. Like always, we need to handle jQuery's ready event. On the page load, we will display the initial prices, just as we did it in the admin page. Following script initializes the required variables, objects and calls the getPrices function when the page loads:

$(function () {
    var proxy = $.connection.priceHub;
    var up = '▲';
    var down = '▼';
    var goldPriceSpan = $("#goldPrice");
    var silverPriceSpan = $("#silverPrice");
    var goldPriceHtml;
    var silverPriceHtml;
    var gsPrices = new Array();

    gsPrices[0] = 0;
    gsPrices[1] = 0;

    $.connection.hub.start(function () {
        proxy.server.getPrices();
    });
});

The populatePrices function is a bit heavier as we are changing the color of the span element based on value. Following is the implementation of the populatePrices function:


proxy.client.populatePrices = function (prices) {
    if (gsPrices[0] != 0 && gsPrices[1] != 0) {
        if (gsPrices[0] < prices[0]) {
            goldPriceHtml = prices[0] + " " + up;
            goldPriceSpan.css("color", "green");
        }
        else if (gsPrices[0] > prices[0]) {
            goldPriceHtml = prices[0] + " " + down;
            goldPriceSpan.css("color", "red");
        }

        if (gsPrices[1] < prices[1]) {
            silverPriceHtml = prices[1] + " " + up;
            silverPriceSpan.css("color", "green");
        }
        else if (gsPrices[1] > prices[1]) {
            silverPriceHtml = prices[1] + " " + down;
            silverPriceSpan.css("color", "red");
        }
    }
    else {
        goldPriceHtml = prices[0];
        silverPriceHtml = prices[1];
    }

    goldPriceSpan.html(goldPriceHtml);
    silverPriceSpan.html(silverPriceHtml);
    gsPrices = prices;
};

Save everything and open the admin page in a browser. Open the client page on another browser window. Once both the pages are loaded on browsers,  modify the values on the client page and see the magic in action!!!


Gold silver prices


Here we go. As soon as we change the values in the admin page, the value changes on the client page also. This shows the power of SignalR. SignalR helps a lot in such applications. We didn't worry about notifying the client when the value changes on the server at all. Implementation on client and server side were totally based on business. Rest of the things were managed by SignalR.

I apologize about the amount of code included in this post, but I couldn't help it. Hope you understand that :)


You can download the source code using this link: Download Source

Happy coding!

2 comments:

  1. Silver Gold Bull is a highly reputable precious metals dealer. They will provide you with bargain, live prices and ensure your precious metals arrives to your door discreetly and fully insured.

    ReplyDelete
  2. Good article
    Well explained...
    Write more with details explantion
    Thanks

    ReplyDelete