Sunday, June 15, 2014

Broadcasting Real time Quotes with SignalR 2.0 and ASP.NET MVC 5.0

This demo shows you how to use SignalR framework to create a trading system that shares the latest bid/ask price with other traders in real time. In each browser trader will place their order in and click "Buy" or "Sell". The hub in SignalR broadcasts prices to all other traders.The SignalR library dynamically generate a script file at runtime to manage the communication between jQuery script from the client ("View" page) and server-side code.




1. In Visual Studio 2013, create a C# ASP.NET application that targets .NET Framework 4.5.2, name it MVCTest, and click OK.

2. In the New ASP.NET Project dialog, select MVC, and click Change Authentication.

3. Select No Authentication in the Change Authentication dialog, and click OK.

4. Add the SignalR library to an MVC 5 application. Open the Tools | Library Package Manager | Package Manager Console and run the following command. install-package Microsoft.AspNet.SignalR

5. In Solution Explorer, right-click the project, select Add | New Folder, and add a new folder named Hubs.

6. Create a newSignalR server hub. Right-click the Hubs folder, click Add | New Item, select the Visual C# | Web | SignalR node in the Installed pane, select SignalR Hub Class (v2) from the center pane, and create a new hub named TradeHub.cs that sends last quotes to all clients.The TradeHub class derives from the Microsoft.AspNet.SignalR.Hub class.

7. Create public methods on your hub class and then access those methods by calling them from jQuery scripts in a "View" page. Replace the code in the TradeHub class with the following code.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
namespace MVCTest.Hubs
{
    public class TradeHub : Hub
    {
        public void Buy(string security, string numberofshares, string price)
        {
            // Call the updateBid method to update Bid prices.
            Clients.All.updateBid(security, numberofshares, price);
        }
        public void Sell(string security, string numberofshares, string price)
        {
            // Call the updateAsk method to update Ask Prices.
            Clients.All.updateAsk(security, numberofshares, price);
        }
    }
}


8. Set up mapping to the hub when the application starts. In SignalR 2.0, this is done by adding an OWIN startup class, which will call MapSignalR when the startup class' Configuration method is executed when OWIN starts. The class is added to OWIN's startup process using the OwinStartup assembly attribute. In Solution Explorer, right-click the project, then click Add | OWIN Startup Class. Name the class Startup and click OK. Change the contents of Startup.cs to the following:


using Owin;
using Microsoft.Owin;
[assembly: OwinStartup(typeof(MVCTest.Startup))]
namespace MVCTest
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Any connection or hub wire up and configuration should go here
            app.MapSignalR();
        }
    }
}

Note: In SignalR 1.0, Open the Global.asax file for the project. Add a call to the method RouteTable.Routes.MapHubs(); as the first line of code in the Application_Start method.This  registers the default route for SignalR hubs

9. Edit the HomeController class found in Controllers/HomeController.cs and add the following method to the class. This method returns the Trade view that you will create in a later step.

 public ActionResult Trade()
        {
            return View();
        }     


10. Create a web page which hosts the SignalR JavaScript client and interacts with the server. Right-click the Views/Home folder, and select Add... | View. In the Add View dialog, name the new view Trade. "Trade" is used by clients. First, it declares a proxy for our hub (TradeHub). And yes, our code says "tradeHub" with lowercase t thanks to Javascript convention. Then  our view calls TradeHub.Buy (when clients want to buy some shares) and TradeHub.Sell (when clients want to sell some shares) to send a new quote from client and share with everybody else. We use Microsoft.AspNet.SignalR.Hub.Clients property to access all clients connected to this hub by calling jQuerys function (updateBid and updateAsk) to update clients with the latest quotes. The TradeHub class on the server calls these two functions to push latest quotes to all clients. connection.hub.start() starts the connection and then passes it Buy/Sell functions to handle "click" event on the "Sell" or "Buy" button. Replace the contents of Trade.cshtml with the following code.

@{
    ViewBag.Title = "Trade";
}
<h2>Realtime Trading System</h2>
<div class="container">
    Security:
    <input type="text" id="security" />
    <br />
    Number of Shares:
    <input type="text" id="numberofshares" />
    <br />
    Price:
    <input type="text" id="price" />
    <br />
    <input type="button" id="buy" value="Buy" /> 
    <input type="button" id="sell" value="Sell" />
    <p></p>
    Last Bid:
    <input type="text" id="bid" />
    Last Ask:
    <input type="text" id="ask" />
</div>
@section scripts {
    <!--Script references. -->
    <!--The jQuery library is required and is referenced by default in _Layout.cshtml. -->
    <!--Reference the SignalR library. -->
    <script src="~/Scripts/jquery.signalR-2.0.3.min.js"></script>
    <!--Reference the autogenerated SignalR hub script. -->
    <script src="~/signalr/hubs"></script>
    <!--SignalR script to update the trade page.-->
    <script>
        $(function () {
            // Reference the auto-generated proxy for the hub.
            var trade = $.connection.tradeHub;
            // Create a function that the hub can call back to display new quotes.
            trade.client.updateBid = function (security, numberofshares, price) {
                // update the last bid price on the page.
                $('#bid').val(htmlEncode(price));
            };
            trade.client.updateAsk = function (security, numberofshares, price) {
                // update the last ask price on the page.
                $('#ask').val(htmlEncode(price));
            };
            // Get the security, number of shares, and price.
            $('#security').val('AAPL');
            $('#numberofshares').val('10');
            // Set initial focus to message input box.
            $('#price').focus();
            // Start the connection.
            $.connection.hub.start().done(function () {
                $('#buy').click(function () {
                    // Call the Buy method on the hub.
                    trade.server.buy($('#security').val(), $('#numberofshares').val(), $('#price').val());
                    // Clear text box and reset focus for next price.
                    $('#price').val('').focus();
                });
                $('#sell').click(function () {
                    // Call the Sell method on the hub.
                    trade.server.sell($('#security').val(), $('#numberofshares').val(), $('#price').val());
                    // Clear text box and reset focus for next price.
                    $('#price').val('').focus();
                });
            });
        });
        // This optional function html-encodes messages for display in the page.
        function htmlEncode(value) {
            var encodedValue = $('<div />').text(value).html();
            return encodedValue;
        }
    </script>
}

11. Press F5 to run the project. In the browser address line, append /Home/Trade to the URL of the default page for the project. The Trade page loads in a browser. Enter Ticker name, Number of Shares, Price and click "Buy or Sell" button. Open another browser and see the latest bid or ask text fields in realtime.