Quantcast
Channel: Rick Schott :: devlpr.net » AJAX
Viewing all articles
Browse latest Browse all 10

Building a demo chat app in MVC3, backbone.js and a little SignalR for fun…

$
0
0

I have been doing a lot of reading lately on backbone.js. One of the key features I wanted to explore was it’s concept of Models and how it keeps the server side in sync with RESTful JSON endpoints.

What is backbone.js?

Backbone supplies structure to JavaScript-heavy applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.

I started searching the internet to find an example in the .NET world, surely someone has an example already?  I did run across a few posts that got me in the right direction:

The Backbone.js Todo List Sample, Refactored – Part 1 via @robconery
ASP.NET MVC3 RESTful application tutorial with Backbone.js – Part I
ASP.NET MVC3 RESTful application tutorial with Backbone.js – Part II
ASP.NET MVC3 RESTful application tutorial with Backbone.js – Part III
A Backbone.js demo app (Sinatra Backend) via ryandotsmith

The BitCandies series was more than I needed, the last article with Sinatra is what I was looking for.  All I wanted to see was how backbone.js posts to the RESTful endpoints.   If I could see that in action I knew I could do the same with MVC3 JsonResults in a Controller.

The chat demo:
This demo uses MVC3 Controllers as the RESTful JSON endpoints utilizing the Json ActionResult. I also made a MVC3 Model called Message to keep the client and server-side parity. I cheated with persistence using a static class, no database needed to run the demo. The original demo I forked from used setInterval to poll the server for new messages. This worked but for only one client. I wanted this to work like a real chat app would, so I replaced that with SignalR to let the clients know new messages have arrived and to update their data. I know I could replace the Controllers with SignalR all together but this is a demo to show how to use all the pieces, not a best practices.

/Views/Shared/_Layout.cshtml(script references needed)

    .........
    <script src="@Url.Content("~/Scripts/jquery-1.6.4.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/underscore.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/backbone.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.signalR.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/signalr/hubs")" type="text/javascript"></script>
    .........
    </body>
    <script src="@Url.Content("~/Scripts/application.js")" type="text/javascript"></script>
    .........

/Scripts/application .js (this is basically the single page app initializer for this example)

// SignalR Proxy created on the fly
var chat = $.connection.chat;

var Message = Backbone.Model.extend({});

var MessageStore = Backbone.Collection.extend({
 model: Message,
   url: '/messages'
});
var messages = new MessageStore;

var MessageView = Backbone.View.extend({

   events: { "submit #chatForm" : "handleNewMessage" }

  , handleNewMessage: function(data) {
    var inputField = $('input[name=newMessageString]');
    messages.create({ content: inputField.val() });

    //signalr call to server
    chat.send("dummy message, just signaling")
            .done(function () {
                console.log('Success!')
            })
            .fail(function (e) {
                console.warn(e);
            })
    inputField.val('');
  }

  , render: function() {
    var data = messages.map(function(message) { return message.get('content') + 'n'});
    var result = data.reduce(function(memo,str) { return memo + str }, '');
    $("#chatHistory").text(result);
    return this;
  }

});

messages.bind('add', function(message) {
  messages.fetch({success: function(){view.render();}});
});

var view = new MessageView({el: $('#chatArea')});

//replaced with SignalR
//setInterval(function(){
//  messages.fetch({success: function(){view.render();}});
//},10000)

// Declare a function on the chat hub so the server can invoke it
chat.reloadMessages = function (message) {
    //server callback, reload messages from server via backbone!
    messages.fetch({ success: function () { view.render(); } });
};

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

//get any messages on load, .fetch is backbone.js working here
messages.fetch({ success: function () { view.render(); } });

/Models/MessageModels.cs

namespace BackboneMVC3SignalR.Models
{
    public class Message
    {
        public string content { get; set; }
    }

}

/Controllers/MessagesController.cs

namespace BackboneMVC3SignalR.Controllers
{   
    public class MessagesController : Controller
    {
        //
        // GET: /Messages/

        public ActionResult Index()
        {
            List<Message> s = new List<Message>();
            if (GlobalVariables.Messages != null)
            {
                s = GlobalVariables.Messages;

            }

            return Json(s, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public ActionResult Index(string content)
        {
            List<Message> s = new List<Message>();
            if (GlobalVariables.Messages != null)
            {
                s = GlobalVariables.Messages;
                
              
            }
            s.Add(new Message{ content = content});
            GlobalVariables.Messages = s;
         
           
            return Json(s, JsonRequestBehavior.AllowGet);
           
        }
        
      
    }
}

/Hubs/Chat.cs

namespace BackboneMVC3SignalR.Hubs
{
    public class Chat : Hub
    {
        public void Send(string message)
        {
            // Call the reloadMessages method on all clients
            Clients.reloadMessages(message);
        }
    }
}

Full working demo can be found on GitHub.


Viewing all articles
Browse latest Browse all 10

Trending Articles