Click here to Skip to main content
12,821,670 members (34,733 online)
Click here to Skip to main content
Add your own
alternative version


42 bookmarked
Posted 29 Oct 2012

Building ASP.NET applications using Knockout.js with a server side defined view model

, 1 Nov 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
Let's build a simple framework that allows to have the power of knockout.js with no JavaScript coding.


Knockout.js is an open source javascript library that allows to apply the Model View ViewModel architectural pattern (MVVM) to web pages. It's a great library that simplifies the development of complex pages with many user interactions.

The only problem is that more code has to be written on the client side, and everybody knows that coding on the client side is much more difficult and time consuming than coding server side (less intellisense support, no compile time check of errors, etc...) 

This small application will show how to define the model, together with it's main functions, in the server side code (C#) without losing the power of client side programming. In this way the code will be more structured and there will be more compile time check on its consistency before deploying it. 

In this example we demonstrate we can build a complex responsive interface without writing a single javascript line of code. Of course moving some processing on the client side with computed fields and functions would improve performance, but when you don't have big models the difference can be really small.


Before reading this article it's important you are familiar with Knockout.js library. For more information about it see the official web site

Using the code 

The sample application is a Visual Studio 2010 web application  that displays an order with its details displayed in paged style.  You can perform some basic operations on the order (change data, edit main data, change prices, quantities, delivery status) and save it. Order data is saved in an xml file Order.xml which is stored in the root directory.   

The page layout is coded in the KnockoutServerSideViewModel.ascx user control. This user control loads the model from the xml file and stores it in an hidden field automatically created by the user control base class (BaseKOUserControl). Another view model  is defined in the DateTime.ascx user control, just to demonstrate the use of more user controls run by a separate view model in the same page.  

From KnockoutServerSideViewModel.ascx:  

<%@ Control Language="C#" AutoEventWireup="true" 
	      Inherits="KnockoutServerSideViewModel.Web.KnockoutServerSideViewModel" %>
<%@ Register src="Pager.ascx" tagname="Pager" tagprefix="uc1" %>

From KnockoutServerSideViewModel.ascx.cs

public partial class KnockoutServerSideViewModel : BaseKOUserControl
    protected override void OnInit(EventArgs e)
        ViewModel = OrderViewModel.GetPagedOrder(1,10);

From BaseKOUserControl.cs:  

private BaseViewModel _ViewModel;
public BaseViewModel ViewModel
        return _ViewModel;
        _ViewModel = value;
        _ViewModel.ModelClass = string.Format("{0}.{1}, {2}", 
           _ViewModel.GetType().Namespace, _ViewModel.GetType().Name, 

protected override void Render(System.Web.UI.HtmlTextWriter writer)
    writer.WriteLine(string.Format("<span id=\"sp{0}\">", this.ClientID));
    writer.WriteLine(string.Format("<script type=\"text/javascript\">" + 
      "\n$().ready(function () {{ var model = setModelFunction(\"{0}\", " + 
      "\"{1}\"); model.init(); ko.applyBindings(model.viewModel, " + 
      "document.getElementById(\"sp{0}\")); }});\n</script>", 
      this.ClientID, this.ControlName));
    writer.WriteLine(string.Format("<input type=\"hidden\" id " + 
      "= \"hd{0}\" value=\"{1}\" />", 
      this.ClientID, HttpUtility.HtmlEncode(Utilities.ConvertToJson(ViewModel))));

The Render method is overridden in order to add the necessary javascript code to start the knockout binding. An hidden field containing the model (serialized in JSON) is added at the end of the user control, and this is surrounded by a span that  allows to have partial knock out binding, so you can have more user controls with server side binding in the same page and they will not disturb one each other.    

The ViewModel object inherits the BaseViewModel, which is a simple class defined like this:  

public class BaseViewModel
   public BaseModel() { }
   public string Function { get; set; }
   public string ModelClass { get; set; }
   public string Argument { get; set; }
   public string RedirectUrl { get; set; } 

The ModelClass property contains the complete .NET description (including assembly and namespaces) of the class  used as ViewModel, and it's set at the beginning of the definition of the ViewModel, during the loading of the page:   

_ViewModel.ModelClass = string.Format("{0}.{1}, {2}", 
           _ViewModel.GetType().Namespace, _ViewModel.GetType().Name, _ViewModel.GetType().Assembly.GetName().FullName);

This is important as the ViewModel instance is passed from the page to server side processing by means of a web service, and knowing the class description allows to deserialize it in the correct type.

The RedirectUrl propery is used to tell the page to redirect to a new url after a call to a server side function (see method SaveAndClose() for an example).

The web service is located in the default.aspx page: 

public static string CallModelFunction(string jsmodel, string className)
    Type t = System.Type.GetType(className);
    BaseModel model = Utilities.ConvertFromJson(jsmodel, t) as BaseModel;
    t.InvokeMember(model.Function, System.Reflection.BindingFlags.InvokeMethod, System.Type.DefaultBinder, model, null);
    return Utilities.ConvertToJson(model);

The BaseViewModel class defines a property named Function which contains the function to be called server side. It is supposed that this function exists as a non static public member of the model class (in the example the model class is OrderViewModel). For example, the Save() method of the model is defined as a non static public member of the  OrderViewModel class:   

public void Save()
    this.LastSavedTime = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString();

All the functions in the model can be defined as void as the responsibility of returning the updated model to the page is demanded to the service.   

In order to correctly define the viewModel in the page (we are on client side now) we used the ko.mapping plugin which takes a json string and deserialize it in a model with observable fields. 

This is the KnockOutBaseManager.js files that contains all the needed functionality to map the model (contained in the viewModel hidden field) and apply the bindings to the page. It also contains the CallModelFunction function that manages the communication with the server side application (it passes the serialized model to the service and maps the returned model to the page). The c$ function can be placed in the knockout binding to call any server side function in the view model. It also accepts an additional argument that is placed in the Argument property of the view model class (for example, to identify in which row we pressed a button) 

 function callFunction(functionName, viewModel) {
        type: "POST",
        url: "/Default.aspx/CallModelFunction",
        data: ko.toJSON({ jsmodel: ko.toJSON(viewModel), className: viewModel.ModelClass() }),
        contentType: "application/json",
        success: function (result) {
            ko.mapping.fromJSON(result, viewModel);
            if (viewModel.RedirectUrl() != "" && viewModel.RedirectUrl() != null) {
                document.location.href = viewModel.RedirectUrl();

function setModelFunction(area, name) {

    var model = function (area) {
        var serviceUrl = "/Default.aspx/";
        //var proxy = new ServiceProxy(serviceUrl);
        var viewModel = ko.mapping.fromJSON($("#hd" + area).val());
        viewModel.c$ = function (functionName) {
            var argument = arguments[1];
            if (typeof argument == 'string' || typeof argument == 'number') {
            callFunction(functionName, viewModel);
        var init = function () {
            if (typeof window["setup_" + name] == 'function') {
                window["setup_" + name](viewModel);
        return {
            init: init,
            viewModel: viewModel
    } (area);
    return model;

The BaseViewModel class contains a property named Argument that is used to pass any custom value that is needed by the server side function to do it's job. For example, in the AddTwoEuro function it is used to pass the index of the detail on which we want to apply the price increase (of course you could use it also to pass the increase value).   

The model definition is located in the Order.cs file. Server side code is really not optimized and it's not very elegant, but the purpose of the example was not to build an elegant Data Access Layer so I decided not to lose too much time on it (If you feel offended by it, just accept my sincere apologize ) 

So, let's summarize the steps that you have to follow if you want to define a new user control with its own model: 

  1. Create a user control that inherits BaseKOUserControl. Its name will be the name of the class, or you can change it by setting the value of the Control name property in the Page_Init method. 
  2. Define a viewModel class that inherits from BaseViewModel.  
  3. Define the ViewModel property in the Page_Load method   
  4. Create the html code with bindings in the usercontrol ASCX file    
  5. Add the necessary functions to the view model class.
  6. Run it!     

This tool was created with the invaluable help of the "Banco del Mutuo Soccorso", a progressive rock band of the 70s 



This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Paolo Costa
Software Developer (Senior)
Italy Italy
Paolo Costa is a software developer with long experience on any kind of .NET application. He lives in Italy and works in Switzerland for a credit card payment acquiring company.

You may also be interested in...


Comments and Discussions

Questionvery good. Pin
Quentin in SA29-Oct-12 19:13
memberQuentin in SA29-Oct-12 19:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170308.1 | Last Updated 1 Nov 2012
Article Copyright 2012 by Paolo Costa
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid