Tag Archives: ASP.NET

Knockout Components – Separating Templates from View Model

Part 1: Dipping your feet into Knockout JS Components

This is the second part in my Knockout JS Components series. So far we have made a simple ‘greeter’ component and used it multiple times. But our HTML template was rather simple and hard coded in the ViewModel as a string. That was fine for a small snippet but for involved templates you don’t want to stick an HTML as string. Rather you would like it to be an independent HTML that’s loaded as required.

Today we’ll see how we can separate the HTML and load it dynamically using another library called RequireJS and a plugin for it (RequireJS-Text).

If you want to follow along, you can get the source code branch for the previous article.

Quick intro to RequireJS

RequireJS is a library that is used for ‘Automatic Module Detection’ and loading of JavaScript modules and references. It was developed by James Burke from Mozilla. It is an open source project hosted on Github with a vibrant community that helps maintain it. It also has good documentation that you can refer to for getting started.

This article is not a RequireJS tutorial, instead we’ll jump right in and start using it, I’ll explain the syntax as we go along. If you have not used RequireJS before, well don’t panic, neither have I Smile.

Installing RequireJS and RequireJS-Text plugins

RequireJS has an official Nuget channel so getting the base library is easy to install via Nuget Package Manager Console, simply type in

install-package requirejs

Next we have to get the Text plugin from Github directly. You can either clone the repo from here https://github.com/requirejs/text or just download the JS file.

Once you have the file, add it to your scripts folder. I have started creating sub-folders for each library because it will come in handy later.

image

  • App/boot : This folder will contain scripts that initialize our libraries
  • App/components : This folder will contain all the components we create. Each component in turn has it’s own folder that may contain the ViewModel, HTML template and more.
  • Scripts/*: As mentioned earlier I’ve moved each library into it’s respective sub-folder under the Scripts folder. So Scripts is essentially for all libraries and frameworks that we will use (and not modify), and everything that we build will go under App.

NOTE: This folder structure is completely arbitrary. I ‘feel’ this works, you can use it, you can totally use your own structure. Just remember where your ‘root’ (folder) is Smile.

Now that we are done with the structure of the libs and sources let’s move on and configure RequireJS.

Configuring RequireJS

Under App/boot folder add a new JS file called require.configure.js. The name is, again, not a part of any convention, use what works for you, just refer it in Index.html correctly).

I have configured RequireJS initially as follows

var require = {
baseUrl: “/”,
paths: {
“bootstrap”: “Scripts/bootstrap/bootstrap”,
“jquery”: “Scripts/jquery/jquery-1.9.0”,
“knockout”: “Scripts/knockout/knockout-3.2.0beta.debug”,
“text”: “Scripts/require/text”
},
shim: {
“bootstrap”: {
deps: [“jquery”]
}
}
}

  • I’ve created a require global variable that has three properties, baseUrl, paths and shim.
  • The baseUrl property sets the root location with respect to which all other paths will be considered.
  • The paths property is assigned an object with name value pairs corresponding to the library names and their relative locations. Not the .js is stripped away from the paths.
  • The shim property provides additional dependency information. Here it shows bootstrap is dependent of jquery. The value ‘jquery’ matches the name used in ‘paths’ above.

Updating references

Now that we have configured RequireJS, technically all we need to do is load RequireJS using the configuration and all should be fine!

Well, let’s update the Index.html file to load RequireJS and remove all other Script references. We update the script references as follows:

<!–<script src=”Scripts/jquery-1.9.0.js”></script>
<script src=”Scripts/bootstrap.js”></script>
<script src=”Scripts/knockout-3.2.0beta.debug.js”></script>–>

<script src=”App/boot/require.config.js”></script>
<script src=”Scripts/require/require.js”></script>

Now you are wondering where is the greeting.js gone and how is it going to be loaded? Well there is no magic, we have a couple of more steps to go.

Add App/boot/Startup.js

In the App/boot folder add a new JavaScript file called startup.js. The name is to help us understand the process, it’s not a convention.

Add the following ‘module-definition’. You can read up about RequireJS Modules here.

define([‘jquery’, ‘knockout’, ‘bootstrap’], function ($, ko)
{
ko.components.register(‘greeter’,
{
require: ‘App/components/greeter/greeting’
});
ko.applyBindings();
});

The Startup module says that it is dependent on jQuery, KnockoutJS and BootStrap. Note, it uses the same names that were used in RequireJS configuration above. The function parameters are instances of the dependencies requested in the array, so if you put another input parameter like boots it would have instance of the bootstrap library. We’ll just keep this in mind for now.

Next it declares a function that has jQuery and KO lib references as input parameters.

In the function we ‘register’ our ‘greeter’ component. Note, that we have moved the registration from the greeting.js to startup. Also note instead of specifying the hard-coded template and view model, we are simply configuring a ‘require’ property, that points to the folder where the greeting.js is (without the js).

Well, that’s the startup configuration. Needless to say, as we add more components they will need to be registered here.

Updating our ‘greeter’ component

The first thing we do is add a greeting.html (name same as JavaScript is again not a convention, just easier to map in our heads).

It contains the same markup that we had hardcoded in the template:

image

Update greeting.js

Finally we update the greeting.js component. We comment out all the old code and replace it with the the following:

define([“knockout”, “text!./greeting.html”], function (ko, greeterTemplate) {
function greeterViewModel(params) {
var self = this;
self.greeting = ko.observable(params.name);
self.date = ko.observable(new Date());
return self;
}
return { viewModel: greeterViewModel, template: greeterTemplate };
});

So essentially we have morphed our component to a RequireJS module. Key thing to note here is use of the text plugin to load load the greeting.html. Require does all the work to load the template and stuff it into the greeterTemplate parameter.

Finally we return an object that KO accepts as definition for a module.

One more thing!

We are almost there. Those paying close attention would have noticed that we didn’t put in reference to the startup.js anywhere. How does RequireJS know how to initialize our app and it’s dependencies?

Back to the Index.html, we update the script tag that refers to RequireJS as follows:

<script data-main=”App/boot/startup” src=”Scripts/require/require.js”></script>

The data-main tag, tells Require that the main module to initialize the app is in that JS file. Thus RequireJS knows what to invoke once fully initialized.

Done!

Conclusion

If you run the application now, you’ll see the same old screen we saw in the first part. So what have we done new? Well plenty:

1. Let RequireJS load scripts dynamically.
2. Separated our KO components’ view from it’s model
3. Defined a central place to register all KO components

What we have not done is do more ‘webby’ stuff like putting in links to other possible pages of the app and creating different types of modules for each page and then showing how our app can navigate to those pages as well as load those dependencies on-demand. That’s what we’ll cover in the next part – Routing!

Source Code

The source is on Github as usual (note, after each article I am branching the code out and keeping the master for the latest updates)!

https://github.com/sumitkm/BuildingSpaUsingKO/tree/Part2

Tagged , , , ,

Dipping your feet into KnockoutJS Components

Last week I saw Steve Sanderson’s NDC 2014 talk on how to build large Single Page Applications using KnockoutJS and other tooling. It struck a chord because SPA is something that I am dealing with right now and really wanted to get neck deep into how to use KO and other tools to build one ‘correctly’.

I have tried with AngularJS in the past and you may have read my multipart series on Devcurry. While I have nothing against AngularJS I still find myself more inclined towards using KO more than anything else. Don’t read too much into it, it’s just me, I like KO!

Anyway, Steve’s talk is very deep and he rightly says, you feel like you are hanging on to a race car when sitting through his talk. So I’ve decided to really slow things down and take it one small bit at a time to see how we can use the latest and greatest version of KO (3.2.0 Beta) to build a front-end framework.

Today we’ll look at something new that’s not available in the release version of KO 3.1 as of date – Components.

Components allow you to build HTML+JS snippets that can be reused just like old server side controls of yester-years or like Directives in AngularJS. They actually mimic an upcoming web standard called Web Components.

Steve also used a set of tooling that I am unfamiliar with, so I’ll try to map stuff he did to how I would do if I were using Visual Studio (as far as possible). Lets get started.

Getting Knockout 3.2Beta

As soon as 3.2 goes live it will be available for use via Nuget and the Nuget Package Manager from inside Visual Studio. Today you can download the build from the Releases page on KO’s Github repo – https://github.com/knockout/knockout/releases

If you are a JS ninja you can get the entire library source and build it using NPM and Grunt.

Starting with a clean slate

I’ll start with an empty Web Project in Visual Studio 2013.

Screenshot 2014-07-18 20.55.33

Screenshot 2014-07-18 20.55.57

Screenshot 2014-07-18 20.56.28

As you can see, we get a really really empty template. If you run this in VS, you will get an error saying you don’t have directory browsing permissions.

The Home Page

Since our project is all clean, let’s first install Bootstrap that we’ll use for styling. In the PM console type:

install-package bootstrap

This gives us the following folder structure, where Content has the StyleSheets and Scripts has the JavaScripts required.

image

Now add a new HTML page to the root of the project, call it Index.html (or home.html)

image

Thanks to Visual Studio I have forgotten how to setup a basic startup page using Bootstrap. Serves me right, that, I have to scratch my head and wonder ‘now what’:

image

After ‘considerable’ struggle Winking smile, I update the HTML to include Bootstrap styling and jQuery references.

<!DOCTYPE html>
<html xmlns=”
http://www.w3.org/1999/xhtml”>
<head>
<title>Dipping your feet into KnockoutJS Components</title>
<link href=”Content/bootstrap.css” rel=”stylesheet” />
<link href=”Content/bootstrap-theme.css” rel=”stylesheet” />
</head>
<body>
<div class=”navbar navbar-inverse navbar-fixed-top”>
<div class=”container”>
<div class=”navbar-header”>
<button type=”button” class=”navbar-toggle” data-toggle=”collapse” data-target=”.navbar-collapse”>
<span class=”icon-bar”></span>
<span class=”icon-bar”></span>
<span class=”icon-bar”></span>
</button>
<a class=”navbar-brand” href=”/”>KO Components</a>
</div>
</div>
</div>
<div class=”container body-content” style=”padding-top:50px”>
<h2>Dipping your feet into KnockoutJS Components</h2>
<hr />
</div>
<footer class=”navbar navbar-fixed-bottom”>
<p>&copy; 2014 – Still Learning </p>
</footer>
<script src=”Scripts/jquery-1.9.0.js”></script>
<script src=”Scripts/bootstrap.js”></script>
</body>
</html>

Now if I run this in Visual Studio we’ll get the following page:

image

Let’s see some KO!

I am assuming you have downloaded the KO library as instructed above, so add it to the scripts folder and add a reference to it in our HTML file.

image

Now our App is going to be all HTML and JavaScript and I don’t see the need for CSHTML files at the moment. So let’s create an App folder in the application to consolidate ‘our stuff’.

We add a folder called App and add a js file called greeting.js to it.

In this file we add a simple view model with two properties greeting and date. For now we’ll hardcode the greeting to a standard “Hello World”.

var viewModel = {
greeting: ko.observable(“Hello world!”),
date: ko.observable(new Date())
};

$(function () {
ko.applyBindings(viewModel);
});

Finally we add reference to this script in our Index.html and add a couple of spans to show our greeting.


<div class=”container body-content” style=”padding-top:50px”>
<h2>Dipping your feet into KnockoutJS Components</h2>
<hr />
<div class=”container-fluid”>
<div> Hello <span data-bind=”text: greeting”></span></div>
<div> It is <span data-bind=”text: date”></span></div>
</div>
</div>

<script src=”Scripts/jquery-1.9.0.js”></script>
<script src=”Scripts/bootstrap.js”></script>
<script src=”Scripts/knockout-3.2.0beta.debug.js”></script>
<script src=”App/greeting.js”></script>

Refresh the Index.html on your browser and you should see something similar:

image

Now if you are wondering what’s so great about this, it’s exactly how KO works, you are right!

Where are my komponentz?!?

Well, let’s say we want to convert our ‘Greeting’ HTML + View Model into a reusable component that can be applied anywhere we want? Hello KO components!!!

Change the greeting.js to the following:

ko.components.register(‘greeter’, {
    // The register method needs a config object with
// 2 properties

template: // template is a string with the HTML template to apply
// Here we have directly hardcoded the string we originally
// had in index.html
        “<div class=’container-fluid’>” +
“<div> Hello <span data-bind=’text: greeting’></span></div>” +
“<div> It is <span data-bind=’text: date’></span></div>” +
“</div>”,
viewModel: function(){ // viewModel that can be an object or function
        greeting = ko.observable(“Hello world!”);
date = ko.observable(new Date());
}
});

$(function () {
ko.applyBindings();
//We have removed the explicit reference to the viewModel
});

As we can see above, we have used the new ko.components API to declare a new component called ‘greeter’ (first parameter).

The component needs two parts to be initialized properly, one is the HTML template (in the template) property, and other is the View Model in the viewModel property of the initialization object.

As of now, we have hardcoded the HTML that we had added to our Index.html as the template. Later on, we’ll see how to get it from a separate file etc.

We have used the constructor method technique to define the view Model with the same two properties we had earlier. Why? We’ll see in a minute.

Now that our ‘component’ is ready how do we ‘use’ it? Simple, the name of the component is also the name of the tag, so switch back to Index.html and update the body as follows:

<div class=”container body-content” style=”padding-top:50px”>
<h2>Dipping your feet into KnockoutJS Components</h2>
<hr />
<greeter></greeter>
</div>

Refresh your Index.html in browser and you’ll see things still work as they were! Congratulations, you’ve just built your first component.

Passing Parameters to components

Well, the hard coded Greeting is not quite flexible, what if we wanted to pass in a message to the component?

It is very simple to pass parameters into a component. Add a ‘params’ attribute to the tag and pass in name: value pairs. You will get it as an object in the constructor of your viewModel and you can use it accordingly.

So change the component setup in greeting.js as follows

ko.components.register(‘greeter’, {
// The register method needs a config object with
// 2 properties
template: // template is a string with the HTML template to apply
// Here we have directly hardcoded the string we originally
// had in index.html
“<div class=’container-fluid’>” +
“<div> Hello <span data-bind=’text: greeting’></span></div>” +
“<div> It is <span data-bind=’text: date’></span></div>” +
“</div>”,
viewModel: function(
params){ // viewModel that can be an object or function
greeting = ko.observable(params.name);
date = ko.observable(new Date());
}
});

Next update the Index.html to pass parameters to our component.

<greeter params = ‘name: ” Sumit!”‘></greeter>

Refresh the page and you see the following:

image

Copy paste multiple <greeter … /> instances and pass different names to them

<greeter params=’name: ” Sumit!”‘></greeter>
<greeter params=’name: ” Optimus!”‘></greeter>
<greeter params=’name: ” Bumblebee!”‘></greeter>

Refresh Index again and things work as expected!

image

Congratulations, you have built your first KO component!

This concludes the first 15 (approx.) minutes of Steve’s talk. Lots of more stuff is in store. As I explore these things, I’ll continue to share what I learn, first of which will be using RequireJS and Automatic Module Detection. So watch out for the next part in the series.

Source code on my Github repo here – https://github.com/sumitkm/BuildingSpaUsingKO/tree/Part1

Tagged , , , ,

QuickBytes: Decimal to Indian Numeric formatting

image

Recently I came across the need to format Decimal as Currency, but force it down to Indian/Vedic/South Asian numeric formatting (thousands, lacs, crores etc.) instead of the standard Arabic/Metric system (thousands, hundred thousands, million, billion etc.).

The answer was easily found in this StackOverflow thread. The code snippet is reproduced here:

string fare = “123000.0000”;
decimal parsed = decimal.Parse(fare,
CultureInfo.InvariantCulture);
CultureInfo hindi = new CultureInfo(“hi-IN”);
string text = string.Format(hindi, “{0:c}”, parsed);

The above code gives us the following string

₹ 1,23,000.00

However, the next requirement was to keep the decimals and formatting but remove the Currency symbol. Another quick search gave us this little gem from Jon Skeet on StackOverflow. Essentially he extracted the NumberFormatInfo from the CultureInfo and reset the Currency Symbol to an empty string. Then use the NumberFormatInfo instance to format the decimal value. So the above code can be modified as follows:

string fare = “123000.0000”;
decimal parsed = decimal.Parse(fare,
    CultureInfo.InvariantCulture);
CultureInfo hindi = new CultureInfo(“hi-IN”);
NumberFormatInfo hindiNFO =
    (NumberFormatInfo)hindi.NumberFormat.Clone();
hindiNFO.CurrencySymbol = string.Empty;

string text = string.Format(hindiNFO, “{0:c}”, parsed);

This gives us the following string. It’s difficult to see here but there is a leading space that you might want to trim if you need to.

1,23,000.00

A Sample Application

I thought it would be a fun project to write some code that gives you the above code for any Culture Code you want, so I setup a basic ASP.NET project and deployed it for free on the AzureWebsites. You can see it in action here – Currency Formatter on Azure WebSites

  • I spun up Visual Studio 2013 and setup a default MVC project.
  • Next I updated KnockoutJS to the latest version

PM> update-package KnockoutJS

  • Added an Entity to encapsulate the culture information. I referred to this list on MSDN as my source.

public class IsoCultureInfo
{
    public int Id { get; set; }
    public string LanguageCultureName { get; set; }
    public string DisplayName { get; set; }
    public string CultureCode { get; set; }
    public string ISO639xValue { get; set; }
}

  • Scaffolded up an EntityFramwork controller: CultureInfoController
  • Added two methods to the CultureInfoController that return JsonResults
  • The first one simply returns the entire list of IsoCultureInfo objects in the DB

public JsonResult List()
{
    return Json(db.IsoCultureInfoes.ToList(), JsonRequestBehavior.AllowGet);
}

  • The second one formats the predefined text based on the incoming Culture Name and returns the formatted text as a JSON object.

public JsonResult FormattedText(string id)
{
     try
     {
         string fare = "123000.0000";
         decimal parsed = decimal.Parse(fare, CultureInfo.InvariantCulture);
         CultureInfo cultureInfo = new CultureInfo(id);
         NumberFormatInfo cultureNFO = (NumberFormatInfo)
cultureInfo.NumberFormat.Clone();
         //cultureNFO.CurrencySymbol = string.Empty;
         string text = string.Format(cultureNFO, "{0:c}", parsed);
         return Json(new { formattedCurrency = text });
      }
      catch (Exception ex)
      {
          return Json(new { formattedCurrency = "N/A" });
      }
}

  • Both these methods are invoked from the Index HTML. The UI is databound to a Knockout ViewModel. This is defined in the script formatCurrency.js

/// <reference path="_references.js" />

var isoCultureInfo = {
    LanguageCultureName : ko.observable(“”)
};

var viewModel = {
    dataList: ko.observableArray([]),
    formattedString: ko.observable(“Test”),
    selectedCulture: ko.observable(isoCultureInfo)
};

$(document).ready(function () {
    $.ajax(“/CultureInfo/List”,
        {
            type: “GET”,
            contentType: “text/json”
        }).done(function (data) {
            viewModel.dataList = ko.mapping.fromJS(data);
            ko.applyBindings(viewModel);

            viewModel.selectedCulture.subscribe(function(newValue){
                if (newValue.LanguageCultureName() != ”) {
                    var data = { “id”: newValue.LanguageCultureName() };
                    $.ajax(“/CultureInfo/FormattedText”,
                        {
                            type: “POST”,
                            contentType: “application/json”,
                            data: JSON.stringify(data)
                        }).done(function (data) {
                            viewModel.formattedString(data.formattedCurrency);
                        }).error(function (args) {
                            alert(“”);
                        });;
                };
            });
        }).error(function () {

        });
});

  • Finally I updated the Index.cshtml of the Home Controller to show the dropdown with the list of culture info.

        Select Culture: <select id="cultureOptions"
                                class="form-control"
                                data-bind="options: dataList(), optionsText: 'LanguageCultureName', value: selectedCulture, optionsCaption: 'Choose...'"></select>

  • Added a <ul> to show all the property values of the selected Culture

<ul>
    <li>Language Culture Name: <b><span data-bind="text: LanguageCultureName"></span></b></li>
    <li>Display Name: <b><span data-bind="text: DisplayName"></span></b></li>
    <li>Culture Code: <b><span data-bind="text: CultureCode"></span></b></li>
    <li>ISO 639x Value: <b><span data-bind="text: ISO639xValue"></span></b></li>
</ul>

  • Next we have a <pre> section which contains the code that changes as per the selected Culture.

<pre>
string fare = “123000.0000”;
decimal parsed = decimal.Parse(fare, CultureInfo.InvariantCulture);
CultureInfo cultureInfo = new CultureInfo(<b><span id=”currentCulture” data-bind=”text: LanguageCultureName”></span></b>);
NumberFormatInfo cultureNFO = (NumberFormatInfo)cultureInfo.NumberFormat.Clone();
// If you don’t want the CurrencySymbol, uncomment the following line
// cultureNFO.CurrencySymbol = string.Empty;
string text = string.Format(cultureNFO, “{0:c}”, parsed);
</pre>

  • Finally we have a span to show the formatted string returned after we have selected the Culture Info

Formatted String: <b><span data-bind="text: $parent.formattedString"></span></b>

Conclusion

The code snippet changes as you select the Culture Info in the dropdown and you can copy paste it directly. I deployed it on a free Azure Website, how? That’s for another day Smile.

Tagged , ,

A Minor Gotcha when using jquery.mobile in MVC4

Yesterday I was playing around with the jquery.mobile package from Nuget and found an interesting gotcha.

I had a project from the MVC4 WebAPI template (note: WebAPI doesn’t have anything to do with it). I wanted to add Mobile support to it, so I installed the jquery.Mobile.Mvc package through the package manager console. The idea was I would use the ViewSwitcher framework to create mobile views with appropriate extensions. But to my surprise my edit views started getting buttons that looked like Mobile buttons.

image

I also got exceptions in jquery.mobile js module like the following.

image

I started scratching my head wondering why was the mobile rendering kicking in when I didn’t have any mobile views created?

Turns out, that when you install jquery.Mobile.MVC or the standalone jquery.mobile nuget packages, the new MVC4 Bundling and minification functionality rolls up all the js files together in the _Layout.cshtml. As a result jquery.mobile kicks in and tries to convert everything into mobile layout.

image

Possible Solution

There is an easy way out.

After you have installed jQuery.mobile under the Scripts folder create a ‘Mobile’ folder and move jquery.mobile* files there.

Before                                    After   

image image

This will ensure the regular views don’t load jQuery Mobile scripts.

Now update the _layout.Mobile.cshtml to point to the updated location for jQuery.mobile scripts

image

You can do the same for the css to if you want to keep a clear separation.

Hope this helps you some head scratching. To me it seems the Nuget Package should be updated. But I’ll leave the solution to the biggies Smile.

Tagged , , , , ,

Fun with @SignalR

This article has grown a little long in the tooth because SignalR has changed significantly since this was written more than a year ago.
I recently co-wrote a new article with Suprotim Agarwal in the DNC Magazine. If you are a .NET Dev I strongly recommend you subscribe to this Free Bi-monthly Magazine. The source code for the article is on Github Repository of DotNetCurry. You can see the sample live here.

Background

For the past several months I have noticed David Fowler, Damien Edwards, Phil Haack and a few other MS Techies I follow on twitter, tweet excitedly about a new framework called SignalR. I didn’t understand the excitement fully and to be honest didn’t try too hard to figure out.

Yesterday Scott Hanselman published this article and re-distributed a link to an article which he wrote end of August, 2011. After going through both, I really wanted to take a closer look at SignalR, and while trying to get his ‘…monkey typing Shakespeare…’ code working I finally had the ‘Ah ha!’ moment.

I just had to come up with this quick and dirty sample to demonstrate a use for SignalR and since I want the bragging rights for it, I am going to throw it up as is without bothering about the niceties of a Nuget package or sample.

UPDATE: I have deployed a working sample of this application at http://apps.apphb.com/funwithsignalr

The Idea

First time I saw Google Wave’s technology demo where they showed multiple people editing/reviewing the document at the same time, it blew me away. I was fascinated by it, but told myself I was too ‘javasciptically challenged’ to design such an Async client side framework.

When my tubelight** finally came on, SignalR was the obvious way to do it. Following is my first rough cut that as of now only syncs content. We’ll get to the fancy colored carets at a later point (hopefully in another article).

**In India one is referred to as a tubelight if something strikes late. Back in the days of non-electronic ballasts for fluorescent lighting, the tubes used to flicker for few seconds before turning on.

Please go through Scott’s articles or SignalR documentation to understand SignalR better. I make no attempts to explain SignalR here (partly because I know precious little and partly it’s such a fantastic framework that you need very little up front to get going).

Head-first into SignalR

To build a scaffolding for SignalR framework you can use plain html with a backend server side SignalR Hub class as Scott demonstrated. But I chose to start off with an ASP.NET MVC 3 project. (Actually my first attempt at ASP.NET MVC 4 using VS 2011 Dev Preview didn’t quite go so well, so I rolled back to the stable releases of ASP.NET MVC 3 on Win 7 using VS 2010).

Setting up a support app as an ASP.NET MVC 3 web project

image

image

I called it ‘FunWithSignalR’ and set it up as an Intranet Application

Adding SignalR to your project using Package Manager Console

image

The package manager console helps you download Nuget packages among other things. If you don’t have it visible you can bring it up from the above menu (in VS 2010)

SignalR is available as a nuget package and all you have to do to include is run the following command in the Package Manager Console

Install-package SignalR

The above command will get all the dependencies you need for SignalR and if your jQuery script files are not up to speed, will get the latest libraries for jQuery too (SignalR client uses jQuery hence the dependency check results in the upgrade). The output will looks something similar to

image

Update jQuery dependencies in Views\Shared\_Layout.cshtml by pointing to the most recently updated jQuery version. As per above image the latest version for me today is jquery-1.6.4.min.js because that’s the one the package manager installed.

Setup the Code First EF Model

We’ll setup a very simple code first model by adding one Entity called BlogPost in our Model folder.

image

Add the DbContext for the BlogPost.

image

Build the solution at this point.

Scaffold the Controller and UI

To use the default scaffold tooling that comes with MVC 3, right click on the Controllers folder and select Add –> Controller.

image

Select the Template, Model and Data Context values as shown above and click Add.

At this point you will have the scaffolding necessary to Add/Edit/Delete BlogPosts.

Adding the ‘Review’ Action

Open the BlogPostController and Copy paste the Get and Post action methods for the Edit action. Change Edit to Review as shown below.

image

Copy the Edit.cshtml and paste it in the View folder. Rename it to Review.cshtml

Update the Index.cshtml such that a ‘Review’ link comes up in the Index

image

Getting SignalR into the game

The Server Side

In your web project create a folder called SignalR (You can call it anything you want, in a real life project this as server side component and could very well reside in a dll of it’s own).

In the SignalR project add a class BlogHub.cs

Add the following code to it


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using SignalR.Hubs;

namespace FunWithSignalR.SignalR
{
[HubName("blogHub")]
public class BlogHub : Hub
{
///
<summary> /// The method called from SignalR client (JS)
/// </summary>
///String Data
///Session ID: Used in this sample to track users
///A boolean value used in the example indicating
/// if incoming value should be appended or overwritten when sent back to
/// other clients
public void Send(string message, string sessnId, bool append)
{
Clients.addMessage(message, sessnId, append);
}
}
}

The Client Side

  • Open Review.cshtml and add the following script references

image

Note: json2.min.js is not packaged with the SignalR nuget. I have packaged it as a part of my code. I got it from Scott’s ‘Shakespeare demo’.

Note 2: /signalr/hubs is dynamically generated at runtime. So don’t worry if it gives a green squidgy right now. It works fine at runtime. Without this reference SignalR client won’t work.

  • Change the Html helper for the Post property from Html.EditorFor(…) to Html.TextAreaFor(…).
  • Add a hidden field to save the session Id in it (this maybe a security hole, need to investigate best practices)

<input id="sessinId" type="hidden" value="@Session.SessionID" />

  • Drop the following script in
<script type="text/javascript">// <![CDATA[
$(function () {
// Proxy created on the fly
var blog = $.connection.blogHub;
// Declare a function on the blog hub so the server can invoke it
blog.addMessage = function (message, sessnId, append) {

var sessId = $('#sessinId').val();

if (sessId != sessnId) {
if (append) {
$('#Post').append(message);
}
else {
$('#Post').val(message);
}
}
};

// Start the connection
$.connection.hub.start();

$("#Post").keyup(function (event) {
// Call the send method on the server

var sessId = $("#sessinId").val();
if (event.keyCode >= 65 && event.keyCode <= 122) {
if (event.shiftKey || (event.keyCode == 32)) {

blog.send(String.fromCharCode(event.keyCode), sessId, true);
}
else {
blog.send(String.fromCharCode(event.keyCode + 32), sessId, true);
}
}
else {
blog.send($("#Post").val(), sessId, false);
}
});
});
// ]]></script>

  • If you see closely this is pretty similar to Scott’s 11 lines of code to get a chat client going.

Changes I have made are:

1. Send message to server on KeyUp event of the Post text area, instead of an explicit button push

2. Send more meta information like the current sessionId and if the keystroke means an append action should take place at the client action of an overwrite action should take place at the client option.

Let it Roll

Run the application and navigate to the BlogPost Index

image

Add a new Post

image

Click on Review

image

Press Ctrl+N to start a new browser instance with the same page. Hit F5 so the session id (the text field next to Save button) changes. Arrange the two browsers side by side.

Type in one Post text area and watch the other one change almost simultaneously

image

As Scott says, Kabooom! brain explodes…..

In Conclusion

To wrap up, we saw how mind numbingly easy it is to use SignalR.

It’s a fantastic abstraction over various techniques available for persistent connections over http. Under the hood it can use websockets or longpolling depending on what’s available.

You can get infinitely creative with it and build fantastic collaborative ASP.NET apps using SignalR backend.

Some day (hopefully) in the near future, I would have overcome my javascript challenges and built a real collaborative editor with all the fancy bells an whistles of Google Docs.

Finally, David Fowler and team, a million thanks for such a fantastic framework. I am loving the ‘just works’ motto Smile. And Scott Hanselman for providing the ‘Aah ha!’ moment, without which I probably would have not given SignalR a look yet.

The Code

The code can be downloaded from here (size 844 KB) (skydrive). It is provided AS IS, with no warranties expressed or implied. You are free to use it without any attribution (but I would love it if you do feed my ego Winking smile).

I have now made the code available on bitbucket Mercurial repository. You can get it from here https://bitbucket.org/sumitmaitra/funwithsignalr

Update

The code in bitbucket now uses Google’s diff-match-patch implementation and is hence Apache licensed now.

Tagged , , , ,
%d bloggers like this: