Tuesday, December 13, 2011

ASP.NET MVVM with ASP.NET MVC 3 and knockout.js

There’s continuously increasing attention to separating presentation layer (HTML + javascript) and business layer (ASP.NET, PHP, etc.) in web development. More and more developers are seeking for supports of MVVM pattern in their web projects.  Among various offerings that exist today, knockoutjs is one of the most promising ones. It’s simple, it’s clean, and it has many core concepts of MVVM covered. On the server side, ASP.NET MVC 3 (and soon MVC 4) has gained great popularity in .Net communities. The purpose of this article is to explore a possible architecture that combines benefits of ASP.NET MVC 3 and knockoutjs and to provide a MVVM design pattern for common web project.

MVVM –> Entities + Views + View Models + (Repositories) + Services –> EVVMRS pattern

Before we go further, let’s reflect on what VM means in the MVVM pattern. In theory VM is an abstracted View, however in reality we often see VM contains other things such as business entities, entity repositories, and logics to invoke services. So here I’d like to make an explicit distinction: to get repositories and services out of VM and make them separate entities in the architecture. And here are the roles under this EVVM(R)S pattern:

  • E: Business entities. These are the entities you manage. Note the entities don’t contain business logics (well, maybe some basic data validations can be allowed).
  • V: Views. These are the UI presentations.
  • VM: View Models. These are the logical views that handles view interactions such as commanding, notifications, etc.
  • R: Repositories. These are where VMs get business entities. Repositories can also serve as the abstraction layer between VMs and Services.
  • S: Services. These are where business logics are encapsulated. Note the Services can be either local or remote. Repository layer provides a location-agnostic abstraction to VMs.

With this pattern, the architecture of a common web-based application can be illustrated as:

image

Where are Business Entities? Business Entities flow through this diagram and transform into different forms as they go. Specifically:

  1. From Database to Service: Services need to interact with databases with database-specific APIs. It can be ADO.Net, Entity framework, cloud storage, or other data-access APIs. Services convert these records into Business Entities. And all business logics should be built on top of these entities.
  2. From Services to Repositories: in the case that Services are local, Repositories can share the same Business Entity types with the Services. For remote Services, however, Repositories often don’t have direct access to Business Entity types defined on the Services. Instead, they’ll use some proxy types (such as the types you get when you add service references by using service metadata), or they’ll use totally different presentations such as XML or JSON objects (often seen in REST-ful calls). Although there are frameworks and tools that allow you to “share contracts” between your clients and servers, but the entities types on each side are still different physical types.
  3. From Repository to View Modes. Usually View Modes share the same Business Entity types with Repositories.
  4. From View Models to Views. View Models annotate Business Entities with change notification properties and supply annotated entities for UI binding to Views.

How to fit ASP.NET MVC 3 and knockoutjs into above pattern

Component Role
HTML View: screen markups and templates that knockoutjs can bind View Models to.
javascript “class” View Models: knockoutjs defines View Models as javascript classes.
javascript Repository: this part is up to you to define & construct. Repositories should encapsulate Service invocations.
JSON objects Business Entities: JSON are used when Services return data to client/Repositories.
C# objects Business Entities: These can be POCO types or Entity Framework types that are used in Service layer.
ASP.Net MVC Controller Services: REST-ful services that return JSON objects.

Under this pattern, MVC Controller will also provide “hook-up” for Views – they return Views to browser. However under this pattern they’ll simply return “untyped” views:

public ActionResult Index()
{
   return View();
}

In parallel MVC Controller provides Service APIs to client. For example, to supply Business Entities as JSON objects:

public JsonResult lisCustomers()
{
      return Json(dataContext.ListCustomers(), JsonRequestBehavior.AllowGet);
}

The corresponding view (.cshtml if you are using razor) contains standard HTML and javascripts only. You’ll not use @model directive anymore. (Of course in the future Microsoft may as well get everything combined!) Instead, you’ll use knockoutjs and jQuery template syntax to create views and binding templates. I won’t go into details here as there are abundant resources on the web.

0 comments:

Post a Comment