Using ucajax to render UserControls via WCF

I recently released an open source project called ucajax hosted on GitHub and also available via NuGet. The project’s main purpose is to render ASP.NET UserControls via web services, currently supporting WCF and WebMethods.   It also comes will a fully functional demo that consumes the NuGet package and can be viewed live here.

There are few limitations such as postbacks, it doesn’t support them.   Ucajax will also strip out resources/form tags…etc and only sends you the content of the UserControl.   This is done for a few reasons.  ASP.NET will get upset if new ViewState or forms get injected into the DOM that it doesn’t know about.

The simplest example is the Load Via Client WCF example.

1. Add ucajax to your project via NuGet:

2. Create a UserControl:

Markup:


<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="UserControlSimple.ascx.cs" Inherits="ucajax.web.Controls.UserControlSimple" %>

<asp:label ID="lblTitle" Text="I am a simple UserControl using asp:label" runat="server"/><br>
<asp:label ID="lblTextProperty1Title" Text="TextProperty1 = " runat="server"/><asp:label ID="lblTextProperty1" Text="" runat="server"/>
<!--and some html--><br>
<asp:hyperlink ID="hlLinkToMe" Text="I am also using asp:hyperlink" NavigateUrl="https://github.com/rickschott/uc-ajax" runat="server"/><br>
<asp:label ID="lblReload" runat="server" Text="Wait 30 seconds and I will reload myself using all the sever-side parameters originally used." /><br>
<asp:label ID="lblDateTime" Text="" runat="server"/><br>
<asp:label ID="lblTextProperty2Title" Text="TextProperty2 = " runat="server"/><asp:label ID="lblTextProperty2" Text="" runat="server"/>

Code-behind:

namespace ucajax.web.Controls
{
    public partial class UserControlSimple : System.Web.UI.UserControl
    {
        public string TextProperty1 { get; set; }
        public bool TextProperty2 { get; set; }
        public bool AjaxAutoRefresh { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            lblTextProperty1.Text = TextProperty1;
            lblTextProperty2.Text = TextProperty2.ToString();
            lblDateTime.Text = "Oh, look at the time: " + DateTime.Now.ToString();
            lblReload.Visible = AjaxAutoRefresh;
        }
    }
}

3. Add some markup to a .aspx:

<div id="ajaxifyspinner" class="ajaxifyspinner">
    <asp:Image ID="imgResultsProgress" ImageAlign="Middle" runat="server" ImageUrl="~/Images/ajax-loader.gif" />
</div>
<div id="AJAXContent">
</div

4. Add some script that will render the UserControl:

var baseUrl = "";
    $(document).ready(function () {
        var model = new $.ucajax.viewModel($.ucajax.DICTIONARY_TYPE.WCF);
        model.ajaxControlViewModel.ControlPath = baseUrl + "Controls/UserControlSimple.ascx";
        model.ajaxControlViewModel.ControlParams.push(new model.keyValuePair("TextProperty1", "Set via JavaScript, rendered via WCF!"));
        model.ajaxControlViewModel.ControlParams.push(new model.keyValuePair("TextProperty2", "True"));
        model.ajaxControlViewModel.ControlParams.push(new model.keyValuePair("AjaxAutoRefresh", "True"));

        $().ucajax({ contentId: 'AJAXContent',
            postData: model,
            RESTUrl:  baseUrl + 'Service/AjaxContent.svc/GetAJAXControl',
            ajaxSpinnerId: 'ajaxifyspinner',
            autoRefresh: true
        });
    });

5. You now have a UserControl rendered via a WCF web service:

Now, go create something and tell me about, would love to hear your feedback!

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

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.