Sunday, May 10, 2015

SignalR-based Live Stock Ticker with Ticker.FSharp

Introduction

It was an awesome weekend, finally got my hands into SignalR and updated the Ticker.FSharp to add a SignalR web sample ticker. In this post I have talked about how easy it was to throw a simple ticker together using the Ticker.FSharp repository and SignalR. The sample can be downloaded from the Github repository page.

Screenshot





Implementation

I added an empty web project to the solution, then added a SignalR Hub, a Javascript file for event handling, an HTML page for the UI. Here is a quick overview of each of those.

SignalR Hub

As we know, the server-side hub is a primitive component of a SignalR application. My sample hub has only two methods, one is called by the client to start up the hub when it gets launched the first time, and other method is called from the server side that reports the ticks generated by Ticker.FSharp. The call to Tick then channels in to the browsers of each user connected.

The full source listing for the hub file can be found at this Github page. I am only discussing the important points.

Here is how the Hub is declared

[HubName("tickerFsharp")] public class TickerFSharpHub : Hub
As you can see, the hub declaration contains the HubNameAttribute which tells the SignalR engine how the hub is going to be located. There are two methods inside the hub, one is StartTicker which is responsible for calling the Ticker.FSharp library and obtaining the IObservable<Tick> object. Here I am fetching the ticks of three symbols together.

[HubMethodName("startTicker")]
public void StartTicker()
{
if (subscription == null)
{
var machine = new DataMachine();
var aapl = this.AddIndicator(machine.GetLiveGoogleApiTicks("AAPL"));
var goog = this.AddIndicator(machine.GetLiveGoogleApiTicks("GOOG"));
var msft = this.AddIndicator(machine.GetLiveGoogleApiTicks("MSFT"));

subscription = aapl.Merge(msft).Merge(goog).Subscribe(t => {

this.Tick(t.Tick.Symbol, t.Tick.Price, t.Tick.LastUpdated.ToString(), t.Up);

});.
}

In the above listing, I am calling the Ticker.FSharp 3 times to get the live feed for three symbols. I am also calling the AddIndicator helper method to garnish the object with an additional property that tells me whether the value went up or down since the last value. And finally, I am calling the Tick method which calls the tick method at the client's side.

public void Tick(string symbol, double price, string lastUpdated, bool up)
{
Clients.All.tick(symbol, price.ToString("###0.00"), lastUpdated, up);
}

The above Tick() method implementation is pretty self-explanatory.

Javascript Event Handling

The JS file has quite the code, I am only discussing the tick() handler that server-side will be calling.

hub.client.tick = function (symbol, price, lastUpdated, up) {
var row = $stockTableBody.find("tr[datasymbol=\"" + symbol + "\"]");
if (row.length == 0) {
var templatedRow = rowTemplate.replace("{Symbol}", symbol)
.replace("{Price}", price)
.replace("{lastUpdated}", lastUpdated);
$stockTableBody.append(templatedRow);
}
else {
var cells = row.first().find("td");
cells.eq(0).html(symbol);
cells.eq(1).html(price);
cells.eq(2).html(lastUpdated);
}
}

The above code is simple, as the tick arrives, it checks to see whether the table already has a row for that symbol, if so it updates the data otherwise it adds a new row for that symbol.


Thats all for this blog, if you want to check out the full source code, I encourage you to visit the Github project page.

Happy coding!

Saturday, May 9, 2015

SignalR - Damien Edwards' MoveShape sample . Getting it to work with latest SignalR + Sample Project

Introduction

I had a good learning experience with SignalR. I started by watching Damien Edwards Video on YouTube. Now I am officially the SignalR newbie and I am hoping to keep climbing this ladder in upward direction :)

In this post I would like to share my experience with the Move Shape example that Damien showed in his video. I initially followed all the instructions as he demonstrated, but I failed to get it to work. I then read through the SignalR documentation and found that the latest version has a few changes since that video was filmed. I corrected the example and this post contains all the things that are different and of course the sample project source code for you to download. So lets get started.

Screenshot


As you may have noticed in the video, this was how the example worked. You drag and move the box in one browser, the box in other browser will follow the movements.




Changes

First thing you would need to change is in the Hub definition file. Or the MoveShapeHub class. There are a couple of changes in the class code.

  1. Hub methods have to be attributed using HubMethodNameAttribute
  2. Instead of calling the client method on Clients object, you have to call it on Clients.All property.

So the new code looks like this (notice the highlights)

    [HubName("moveShape")]
    public class MoveShapeHub : Hub
    {

        [HubMethodName("moveShape")]
        public void MoveShape(int x, int y)
        {
            Clients.All.shapeMoved(Context.ConnectionId, x, y);
        }
    }


The next thing that is changed is the way hub was extended. If you remember the video, he used the $.connection.extend method. But now you just have to define it like a regular prototype

    hub.client.shapeMoved = function (cid, x, y) {
        if ($.connection.hub.id != cid) {
            console.log("Yes");
            $shape.css({ left: x, top: y });
        }
    };

Also notice that instead of hub.shapeMoved, it is now called hub.client.shapeMoved. Next change goes inside the drag handler. Instead of calling hub.moveShape, you have to call hub.server.moveShape.

so the Hub's start-done handler looks like this

    $.connection.hub.start().done(function() {
        $shape.draggable({
            drag: function () {
                hub.server.moveShape(this.offsetLeft, this.offsetTop || 0);
            }
        });
    });


And you're done. Happy coding!

Downloading the sample project

You can download the full-blown VS2013 Solution Here.