MVC on ASP.NET without ASP.NET MVC

by Jan Blomquist 10. February 2010 09:54

Background

MVC (Model View Controller) is an architectural pattern and in many ways the preferred approach for layering your application. ASP.NET MVC is Microsoft's solution to a set of common challenges that face web developers today. Some of these problems are: -

ASP.NET MVC "forces" the developer to model their application according to their MVC architecture and brings greater control and granularity over markup. Because of this, ASP.NET Ajax (or jQuery for that matter) becomes easier to use since you no longer need to deal with for example autogenerated IDs (ie: ctl101_panelContainer_GridView1) which can be hard to use in client-side ajax applications.

Throwing the baby out with the bath water

Another alleged "benefit" of ASP.NET MVC is that the WebForms model is thrown out, so concepts like ViewState, Postbacks and fully templated event driven server controls doesn't exist anymore. This can be a good thing for an html/css/javascript ninja who wants the pedal to the metal and don't like too many abstractions, however I would argue that MVC on top of the WebForms model is far more superior and in this blog we are going to outline the structure of such an application.

An example of a successful ASP.NET MVC implementation today is StackOverflow -one of the most frequently visited websites for professional developers online today. The development of this project is a small group of developers (3?) who work day to day on the project and have deep intrinsic knowledge of it's inner workings. 

ASP.NET MVC might be the right choice for you depending on your requirements, but creating ANY ASP.NET application today without utilizing some form of MVC seems outrageous IMHO. I would put forth the following postulate derived from this claim:

A well designed ASP.NET WebForms application is an MVC application

Let's take a closer look at how you would assemble such an MVC application using the WebForms model. Don't forget the following regarding design patterns: "A a design pattern is not a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations" - Wikipedia

MVC without ASP.NET MVC

We've created a small application that utilizes the MVC pattern on top of the WebForms model today. Currently it's published at one of our build servers.

When you open the sample you can click the (Click here to get the details]) button to expand various code listings and some code explainations. Let's walk through the application structure together. It's a simple list of Tasks that can be filtered by date and contact person. Since the whole idea is to separate the business code/logic from each UI/View I've created a few models and multiple views. The model is basically just a contract (interface) which defines the operations which the controller needs in order to function. Each View must implement the contract so the controller can do it's work. You have full freedom to architect your models as you find suitable and I would recommend you to favor composition over inheritance .


Models

Here's the code for the IActivityModel

Codebehind (C#/.cs)

   1:  namespace Gaia.WebWidgets.Samples.Combinations.WebApps.MVC.Models
   2:  {
   3:      /// <summary>
   4:      /// This is the model that "glues" together the filter and results and is the
   5:      /// main input to the Controller which then works against this model
   6:      /// </summary>
   7:      public interface IActivityModel
   8:      {
   9:          IActivityFilter Filter { get;}
  10:          IActivityList ViewResults { get;} 
  11:      }
  12:  }

 In order to reuse the Filter I've created it as a separate model. Then I went ahead and created a model which will be used to viewed the results based on the filter. This is the IActivityList model which can be seen here:

Codebehind (C#/.cs)

   1:  namespace Gaia.WebWidgets.Samples.Combinations.WebApps.MVC.Models
   2:  {
   3:      using System.Collections.Generic;
   4:      using Utilities;
   5:   
   6:      /// <summary>
   7:      /// Model that allows binding of results to a View
   8:      /// </summary>
   9:      public interface IActivityList
  10:      {
  11:          void View(IEnumerable<CalendarItem> data);
  12:      }
  13:  }

As you can see, the only operation currently needed is the View method which takes an IEnumerable in order to bind the data. By using such a low common denominator, we can bind to almost anything for presentation, even a custom scheduler component if one were to require such functionality.

Views

The sample has defined 3 views (Repeater, GridView and Listbox) + 1 Mock View used in UnitTests. The codebehind file for the GridView View can be seen here:

Codebehind (C#/.cs)

   1:  namespace Gaia.WebWidgets.Samples.Combinations.WebApps.MVC.Views
   2:  {
   3:      using System.Web.UI;
   4:      using System.Collections.Generic;
   5:      using Models;
   6:      using Utilities;
   7:   
   8:      public partial class ActivityListGridView : UserControl, IActivityList
   9:      {
  10:          void IActivityList.View(IEnumerable<CalendarItem> data)
  11:          {
  12:              zGrid.DataSource = data;
  13:              zGrid.DataBind();
  14:          }
  15:   
  16:      }
  17:  }

In this case we created a UserControl, but it could also have been a server control or an arbitrary class also. It just doesn't matter when modelling after the MVC pattern.

Some have argued that you loose control over markup with the WebForms model and that is true when using powerful components like (GridView, Scheduler, Window, TabControl, etc), but it doesn't have to. Here's a code excerpt from the RepeaterView and as you can see this will give you full control over rendered markup:

Markup (ASPX/.aspx)

   1:  <%@ Control 
   2:      Language="C#" 
   3:      AutoEventWireup="true" 
   4:      CodeBehind="ActivityListRepeater.ascx.cs" 
   5:      Inherits="Gaia.WebWidgets.Samples.Combinations.WebApps.MVC.Views.ActivityListRepeater" %>
   6:   
   7:  <gaia:Panel ID="w" runat="server">
   8:      <ul style="border: 1px solid #999; margin: 5px 5px 5px 0px;">
   9:          <asp:Repeater ID="zView" runat="server">
  10:              <ItemTemplate>           
  11:                     <gaia:Label ID="f" runat="server"><li></gaia:Label>
  12:                     <gaia:Label ID="dt" runat="server" Text='<%# Eval("ActivityDate", "{0:ddd dd. MMM}")%>' />
  13:                     <gaia:Label ID="p" Font-Bold="true" runat="server" Text=' <%# Eval("ContactPerson")%>' />
  14:                     <gaia:Label ID="t" ForeColor="red" runat="server" Text='<%# Eval("ActivityName")%>' />
  15:                     <gaia:Label ID="l" runat="server" /></li>
  16:              </ItemTemplate>
  17:          </asp:Repeater>
  18:      </ul>
  19:  </gaia:Panel>

And really? Are abstractions like Window, Scheduler, Grid bad? I would'n want to develop without my reusable server controls!

The C in MVC - Controllers

Ok - we have defined the model and seen the code for some views. Let's examine the Controller and see how that works.

Codebehind (C#/.cs)

   1:  namespace Gaia.WebWidgets.Samples.Combinations.WebApps.MVC.Controllers
   2:  {
   3:      using System;
   4:      using System.Collections.Generic;
   5:      using Utilities;
   6:      using Data;
   7:      using Models;
   8:   
   9:      /// <summary>
  10:      /// This is the Controller in the MVC pattern and it acts as the "hub" and is responsible for
  11:      /// working on the models and implementing business rules, DAL communication, etc
  12:      /// </summary>
  13:      public class ActivityController : ControllerBase
  14:      {
  15:          private readonly IActivityModel _activityModel;
  16:   
  17:          public ActivityController(IActivityModel activityModel)
  18:          {
  19:              _activityModel = activityModel;
  20:          }
  21:   
  22:          public override void Initialize()
  23:          {
  24:              _activityModel.Filter.BindPersons(ActivityDataLayer.GetContacts());
  25:              _activityModel.Filter.When = DateTime.Now.Date;
  26:   
  27:              ViewChanged();
  28:          }
  29:   
  30:          IEnumerable<CalendarItem> GetItems()
  31:          {
  32:              return ActivityDataLayer.GetByDateAndPerson(_activityModel.Filter.When, _activityModel.Filter.SelectedPerson);
  33:          }
  34:   
  35:          public override void ViewChanged()
  36:          {
  37:              _activityModel.ViewResults.View(GetItems());
  38:          }
  39:    
  40:      }
  41:  }

Another model From the code you can see that we take a model as input parameter to the constructor. This model will be the View itself. In the initialize method we set default values for the DateTime filter and populate the list of available ContactPersons from which the UI can select a person. The IActivityFilter also denotes the SelectedPerson so we should have sufficient information to perform a Filter operation and retrieve data.

Notice the call to the View method on the model where the data is passed in. This takes place in the ViewChanged() operation which can be invoked from the UI too. For example in the SelectedIndexChanged event of the dropdownlist. Ok, so now you have seen the three layers in the MVC architecture. The benefits we have seen so far is

  • Disconnected UI from business logic.
  • UI/Client could easily have been something else (Mobile, WinForms, etc)
  • Removed code from the UI where it might introduce "spaghetti code"
  • Stricter adherence to contract lessens error likeliness

Unit Testing

Ok, but how would you go about and test this stuff? We could have tested this in multiple ways, but the easiest is probably to create mock objects that represent the Views and then pass these MockModels as input parameters to the Controller. Here's a few "dummy" examples of some unit tests. I've just faked the unit test framework and you can swap this out with your favorite unit testing framework. 

Codebehind (C#/.cs)

   1:  namespace Gaia.WebWidgets.Samples.Combinations.WebApps.MVC.Tests
   2:  {
   3:      using System;
   4:      using Controllers;
   5:      using Data;
   6:   
   7:      /// <summary>
   8:      /// This is just a "dummy" test-suite to demonstrate that it's easy to write
   9:      /// TDD - Test Driven Development against an MVC application
  10:      /// </summary>
  11:      public class ActivityTests
  12:      {
  13:          public void Test_ActivityController_TestInitialize()
  14:          {
  15:              ActivityModelMock mock = new ActivityModelMock();
  16:              new ActivityController(mock).Initialize();
  17:   
  18:              bool dateInitialized = mock.Filter.When == DateTime.Now.Date;
  19:              DummyAssert.IsTrue(dateInitialized);
  20:          }
  21:   
  22:          public void Test_ActivityController_TestFilter()
  23:          {
  24:              ActivityModelMock mock = new ActivityModelMock();
  25:              new ActivityController(mock).Initialize();
  26:   
  27:              ActivityListMock view = mock.ViewResults as ActivityListMock;
  28:   
  29:              bool sameData = ActivityDataLayer.GetByDateAndPerson(
  30:                  mock.Filter.When, mock.Filter.SelectedPerson).Count== view.CalendarItems.Count;
  31:              DummyAssert.IsTrue(sameData, "Different data based on same filter");
  32:          }
  33:   
  34:          public void Test_ActivityController_TestMockObject()
  35:          {
  36:              ActivityModelMock mock = new ActivityModelMock();
  37:              new ActivityController(mock).Initialize();
  38:   
  39:              ActivityListMock view = mock.ViewResults as ActivityListMock;
  40:              DummyAssert.IsTrue(view != null, "Unable to get test implementation");
  41:          }
  42:   
  43:      }
  44:  }

Suddenly we've created a robust architecture based on the principles of MVC. Also we've taken advantage of all the good things that come for free in Gaia Ajax and we've built on top of the powerful WebForms model on ASP.NET. And we've made our code highly testable and reusable.

Routing / Dynamic Loading

What more could there be? Well, since you're asking we could have implemented dynamic loading of views (routing?) based on some scheme (url, page, configuration, etc) and in fact this sample automatically loads the available Views dynamically and populates the DropDownList with all the Views that implement the model that we are looking for. This functionality is implemented on the page level and allows you to switch out UI/View on-the-fly. Just click here and  try it out for yourself.

Other ASP.NET MVC drawbacks

An author behind one of the ASP.NET MVC books (Jeff Putz) points out some of the ASP.NET MVC drawbacks on his blog

  1. It also lacks the kind of UX encapsulation that we get with Webforms. For example, I have a template based image gallery control that I've used time and time again. The markup that appears in each cell of the table can be anything I want, and I can tell it to leave a "hole" for a template containing an advertisement. All I do is drop it on a Webform and fill in the templates and it automagically works. This kind of reuse isn't in the strictest sense possible in MVC if you're adhering to the design pattern.
  2. The magic of having a simulated stateful form is also gone, with no postback mechanism. The entire event model is thrown out.
  3. Views feel a little like spaghetti code from old ASP (the scripting platform that used the tragic VBscript)
  4. And the biggest concern I have is that developers won't be thinking about security the way they should. It's already possible in Webforms (or any other platform) to put together an HTTP request with the right information to simulate a legitimate user action and do naughty things when the right preventative code is not in place, but it's even easier in MVC. A URL like "/cats/kill/42" is probably intended to execute cat.Lives-- and it's easy to guess. A lot more care has to be taken to validate data and enforce security.

At the moment I don't see any reason to abandon the WebForms model in favor of ASP.NET MVC, generally because we've had MVC for a long time already, but more specifically for the reasons outlined above and in particular because of simulated Windows Forms development experience brought by the WebForms model. I can respect that many developers don't see this from my point of view if they are using jquery/asp.net ajax and similar client-side technologies. The MVC architecture on top of the WebForms model becomes truly aparent with the right tooling and proper abstractions -like Gaia Ajax. The same would go for related techologies like (Google Web Toolkit)

Conclusion

The following quote from Jeff Atwoods blog pretty much summarizes my feelings about the ASP.NET MVC stuff:

"As we work with ASP.NET MVC on Stack Overflow, I find myself violently thrust back into the bad old days of tag soup that I remember from my tenure as a classic ASP developer in the late 90's. If you're not careful bordering on manically fastidious in constructing your Views, you'll end up with a giant mish-mash of HTML, Javascript, and server-side code. Classic tag soup; difficult to read, difficult to maintain."

If you want to comment on the blog, please use our forums at forum.gaiaware.net

Async loading with Non-blocking UI in ASP.NET with Gaia Ajax

by Jan Blomquist 18. January 2010 14:40

 

We've just published a new sample that demonstrates how to create a web page that loads items as they become available and doesn't block the UI. That means you can fully use the Web Application while another thread is spinning on the server doing the hard work.

Click here to view the sample from our nightly published samples application:
http://nightlysamples.gaiaware.net/Combinations/WebUtilities/AsyncLoading/

Or you can pickup a nightly drop here:
http://build.gaiaware.net/Trial/

The idea behind this is not new, but Gaia Ajax makes this so simple to implement and so fast thanks to the automatic diff/merge capabilities of the DRIMR technology which was introduced in Gaia Ajax 3.6. Click here to view a view about Gaia Ajax DRIMR
Sometimes Web Applications are dropped in favor of traditional Desktop applications because of performance requirements. It's not viable to create web applications that requires long time before responding. However, many functions still require lots of processsing before they can return data at all. The ideal way to solve this is the following

  1. Serve up the UI instantly.
  2. Allow the user to start the time consuming task
  3. Deliver the data for consumption in the UI as it becomes available -leaving the application operational. 

Creating the UI for this kind of application is hard enough as it requires you to dig into multi-threading and it's many pitfalls. Creating the UI as a Web Application becomes almost unthinkable as it adds yet another layer of complexity that makes the project run the risk of blowing up. That being said, any sane person reverts to the good old locally installed application with it's drawbacks to solve the problem.

Does it really have to be like that? I will argue in this blog that it's just as easy -or easier? to create a scalable, robust, multi-threaded web application in ASP.NET that doesn't block the UI -than to revert to writing desktop applications.

The reason is partially because ASP.NET is multi-threaded in itself. Each web request is tied to a Worker thread that lives throughout the duration of that page lifecycle. The process of running the lifecycle and generating the control tree is very in-expensive. In Gaia Ajax, the lifecycle running time is even chopped an additional 30%. Almost always the most expensive operation is your I/O threads. These threads often deal with files, databases, webservices and anything else which is not (in-process). I/O is so dramatically more expensive (realtive to worker threads) that Microsoft introduced the Async pattern in ASP.NET 2.0

"The problem with the ASYNC pattern is still that no WebPage is being delivered before all I/O threads are finished with their work". I argue that another option is to serve the WebPage with few or no I/O threads at all. The delivery time of the web application becomes instant.

Does that make any sense?
These I/O calls where there for a reason wheren't they? -Yes, and I am not saying that they are not going to be executed. I am simply saying that you can deliver the results over ajax by using a diff/merge strategy. In Gaia Ajax 3.6 you get automatic diff/merge for free! :-) Also the A in Ajax stands for asynchronous so they don't block the UI either.

But isn't multithreading Evil?
Yes it's evil and if you can avoid it -so you should. However, in .NET we've gotten lots of tools, code, patterns and various ways of dealing with the issue of concurrency. Modern CPU's are not scaling in terms of higher clock speed, but more cores (Link to Intel 48 cores). The LINQ to Parallells project  is now going shipped as part of .NET Framework 4.0. Instead of being afraid of the beast, I think it's time we deal with it and create the next generation of modern web applications utilizing all these cores available to us.

Ok, so how does this relate to Gaia Ajax?
Gaia makes this paradigm easy to implement with no javascript, no bloat and only the state changes are merged down to the client. Also Gaia implements an ajax request queue which only dispatches 1 ajax request at a time allowing for no concurrency issues there. You still have to deal with concurrency, race conditions, etc in your web application, but like I said that's a lot easier with all the stuff that's available to us there.

The following code snippets outline how this simple example was written. It contains 1 aspx file with a button, datagrid and timer and in the codebehind we toggle enabled and visibility properties and kick off the work which goes on in the BackgroundWorkerTask.cs file. The sample was written to be minimalistic and simple and serves more as a proof-of-concept than production ready code. The code is available in the sample too, but I'll paste it in here for your convenience.

Markup (ASPX/.aspx)

   1:   
   2:  <gaia:Button 
   3:      ID="zButton" 
   4:      runat="server" 
   5:      Text="Start Async Operation" 
   6:      OnClick="zButton_Click" />
   7:      
   8:  <gaia:Image 
   9:      ID="zImageLoader" 
  10:      ImageUrl="ajax-loader.gif" 
  11:      runat="server" 
  12:      Visible="false" />
  13:      
  14:  <gaia:GridView 
  15:      runat="server" 
  16:      ID="zGrid" 
  17:      Width="100%"
  18:      AutoGenerateColumns="false"
  19:      CssClass="async-grid">
  20:          <RowStyle CssClass="itemEven" />
  21:          <AlternatingRowStyle CssClass="itemOdd" />
  22:          <Columns>
  23:              <gaia:BoundField 
  24:                  HeaderText="Time" 
  25:                  DataField="ActivityDate" 
  26:                  DataFormatString="{0:HH:mm}" />
  27:              
  28:              <gaia:BoundField 
  29:                  HeaderText="Name" 
  30:                  ItemStyle-Width="50%"
  31:                  DataField="ActivityName" />
  32:              
  33:              <gaia:BoundField 
  34:                  HeaderText="Contact" 
  35:                  ItemStyle-Width="25%"
  36:                  DataField="ContactPerson" />
  37:          Columns>
  38:  gaia:GridView>
  39:   
  40:  <gaia:Timer 
  41:      ID="zTimer" 
  42:      runat="server" 
  43:      Milliseconds="1000"
  44:      OnTick="zTimer_Tick" 
  45:      Enabled="false" >
  46:  gaia:Timer>
  47:   
  48:   

Codebehind (C#/.cs)

   1:  namespace Gaia.WebWidgets.Samples.Combinations.WebUtilities.AsyncLoading
   2:  {
   3:      using System;
   4:      using UI;
   5:      using Utilities;
   6:      using WebWidgets.Effects;
   7:   
   8:      public partial class Default : SamplePage
   9:      {
  10:          const string CollapsedText = "Click here for more details ...";
  11:          const string ExpandedText = "Click here to hide again";
  12:   
  13:          protected void Page_Init(object sender, EventArgs e)
  14:          {
  15:              SetTimerPollingBasedOnNetworkLatency();
  16:              zViewResponse.Text = CollapsedText;
  17:          }
  18:   
  19:          protected void Page_Load(object sender, EventArgs e)
  20:          {
  21:              if (!IsPostBack) BackgroundTask = null;
  22:          }
  23:   
  24:          protected void zButton_Click(object sender, EventArgs e)
  25:          {
  26:              if (BackgroundTask.IsRunning) return;
  27:              BackgroundTask.Data.Clear(); 
  28:              BackgroundTask.RunTask();
  29:              ActivateUiTaskRunning();
  30:              DataBindGridViewToProcessedItems();
  31:          }
  32:   
  33:          protected void zTimer_Tick(object sender, EventArgs e)
  34:          {
  35:              DataBindGridViewToProcessedItems();
  36:              if (!BackgroundTask.IsRunning) DeactiveUiTaskRunning();
  37:          }
  38:   
  39:          private void DataBindGridViewToProcessedItems()
  40:          {
  41:              zGrid.DataSource = BackgroundTask.Data;
  42:              zGrid.DataBind();
  43:          }
  44:   
  45:          private void SetTimerPollingBasedOnNetworkLatency()
  46:          {
  47:              zTimer.Milliseconds = WebUtility.IsLocalhost ? 500 : 1000;
  48:          }
  49:   
  50:          private void DeactiveUiTaskRunning()
  51:          {
  52:              zImageLoader.Visible = false;
  53:              zTimer.Enabled = false;
  54:              zButton.Enabled = true;
  55:          }
  56:   
  57:          private void ActivateUiTaskRunning()
  58:          {
  59:              zTimer.Enabled = true;
  60:              zButton.Enabled = false;
  61:              zImageLoader.Visible = true;
  62:          }
  63:   
  64:          private CustomBackgroundWorker BackgroundTask
  65:          {
  66:              get
  67:              {
  68:                  return Session["worker"] as CustomBackgroundWorker ??
  69:                      (Session["worker"] = new CustomBackgroundWorker()) 
  70:                      as CustomBackgroundWorker;
  71:              }
  72:              set { Session["worker"] = value; }
  73:          }
  74:   
  75:          protected void zViewResponse_Click(object sender, EventArgs e)
  76:          {
  77:              /* some effects for show-off */
  78:   
  79:              bool show = zViewResponse.Text == CollapsedText;
  80:              zViewResponse.Text = show ? ExpandedText : CollapsedText;
  81:   
  82:              if (show)
  83:                  zCodeResponse.Effects.Add(
  84:                      new EffectParallel(
  85:                          new EffectMorph("width: 650px; height: 450px;", 0.5M),
  86:                              new EffectAppear(0.5M)));
  87:              else
  88:                  zCodeResponse.Effects.Add(
  89:                      new EffectParallel(
  90:                          new EffectMorph("width: 0px; height: 0px;", 0.5M),
  91:                              new EffectFade(0.5M)));
  92:          }
  93:      }
  94:  }

Codebehind (C#/.cs)

   1:  namespace Gaia.WebWidgets.Samples.Combinations.WebUtilities.AsyncLoading
   2:  {
   3:      using System;
   4:      using System.Collections.Generic;
   5:      using System.Threading;
   6:      using Utilities;
   7:   
   8:      public class CustomBackgroundWorker
   9:      {
  10:          private bool _isRunning;
  11:          public bool IsRunning
  12:          {
  13:              get { return _isRunning; }
  14:          }
  15:   
  16:          public void RunTask()
  17:          {
  18:              lock (this)
  19:              {
  20:                  if (_isRunning)
  21:                      throw new InvalidOperationException("The task is already running!");
  22:   
  23:                  _isRunning = true;
  24:                  new Thread(DoWork).Start();
  25:              }
  26:          }
  27:   
  28:          private ICollection _data;
  29:          public ICollection Data
  30:          {
  31:              get { return _data ?? (_data = new List()); }
  32:          }
  33:   
  34:          void DoWork()
  35:          {
  36:              try
  37:              {
  38:                  for (int i = 0; i < 15; i++)
  39:                  {
  40:                      lock (Data)
  41:                          foreach (CalendarItem item in CalendarController.CreatItems(new Random().Next(1, 3)))
  42:                              Data.Add(item);
  43:   
  44:                      Thread.Sleep(new Random().Next(300, 2000)); // Random Sleep to simulate variance
  45:                  }
  46:              }
  47:              catch  { /* Task failed (suppress exceptions in demo) */ }
  48:              finally { _isRunning = false; }
  49:          }
  50:      }
  51:  }

Though simple in nature -the async sample demonstrates a truly powerful concept which could give your web applications a boost you'd never thought possible. So give it a spin and if you like it, please drop us a message by email or use our forums : http://nightlysamples.gaiaware.net/Combinations/WebUtilities/AsyncLoading/

 

Time's up! Gaia Ajax 3.6 Alpha Released!

by Jan Blomquist 13. September 2009 21:01

Thank you for your patience and continued belief in our product. It is our vision to bring you the finest quality for ajax development on the ASP.NET platform. The 3.6 version comes with practical innovation previously unavailable to ASP.NET developers. Hopefully it will bring "goosebumps" similar to the ones we had the first time Microsoft unveiled ASP.NET almost a decade ago. 

"3.6 is backwards compatible and introduces a paradigm shift called adaptive rendering"

Links and downloads

  • Click here to download Gaia Ajax 3.6 "alpha"
    Exe with Visual Studio Integration 30 day trial

  • Click here to download Gaia Ajax 3.6 "alpha" - Tar.gz binaries + source - for open source projects
  • Click here to download Gaia Ajax 3.6 "alpha" commercial (requires subscription) 

Highlights from the Gaia Ajax 3.6 release

1. Adaptive Rendering
Adaptive Rendering is a mind-blowing concept that enables dynamic insertion, removal, moving and replacement of individual controls. The concept has far reaching implications and is the breakthrough technology that will make you hunger for Gaia as the building blocks for your UI layer

  • Click here for a sample that demonstrates dynamic inserts and removals of controls and compare it to the usage of traditional partial rendering
  • Click here for a sample of the chess game featuring dynamic control moves
  • Click here for a sample of our "PageFlakes" sample that also features dynamic moves
  • Click here to check out a sample that demonstrates all features of adaptive rendering, including control replacements via databinding
Jan Blomquist has written an extensive review of Adaptive Rendering on his personal blog.

2. Ajax GridView
The Gaia Ajax GridView is a premier example of adaptive rendering as it enables the worlds most advanced GridView for ASP.NET without much code at all. The GridView still supports all the operations like ( filtering, sorting, selection, deletions, updates, etc ) and it's all ajaxified thanks to adaptive rendering.  

  • Click here for a sample that demonstrates the Gaia Ajax GridView in action

3. 100++ new Samples!
In the package you will find a total of 128 samples ranging from minimalistic ones to extensive, almost full applications in themselves. This is all packaged into a new samples framework that simplifies navigation, code view, VB.NET code availability, etc. 

Note: The samples are now utilizing the WAP project type

More...

Gaia Ajax training - two new courses in Oslo, Norway (Early Bird Extended to 20th of September)

by Stian Solberg 3. September 2009 09:00

Gaia Ajax is a powerful web platform for both complex enterprise applications and fast-up-and-running web sites. In many ways Gaia Ajax completes what many developers are missing on the ASP.NET platform both in regards to how easy it should be to create a rich and responsive web experience, but also how to unleash the highest productivity in your daily development. Our customers say they increase their productivity by 30-60% when developing with Gaia compared to other approaches towards web development.

We're happy to announce two brand new courses this year. Based on the feedback we have received, we have split the courses into two different levels: Introduction to Gaia Ajax and Advanced Ajax development with Gaia Ajax. Each course goes over two days.

28-29th of September

Introduction to Gaia Ajax

Agenda
  • Important ASP.NET semantics
  • Get to know the Gaia Server Controls
  • Introduction to the brand new Gaia Ajax GridView (new in 3.6!)
  • Unleash your productivity with Aspects in Gaia
  • Effect library
  • Skinning Gaia
  • Data management with Gaia
  • Debugging, error handling and security with Gaia 

5-6th of October

Advanced Ajax development with Gaia Ajax

Agenda

  • What's new in Gaia Ajax 3.6?
  • Become a Gaia GridView pro! (New in 3.6)
  • Introduction to Dynamic Inserts (New in 3.6)
  • Advanced Aspects and Effects development
  • Build your own extension controls
  • Build your own aspects
  • Advanced web application architecture - best practices with Gaia and ASP.NET 

 


 

Registration: Use our contact form with number of participants and which course you'd like to attend.

Instructor: Jan Blomquist (MVP)

Target Audience: .NET Developers

Max Participants: 12

Language: English

Price: EUR 1100*
Incl.lunch. excl.hotel
* Excluding 25% VAT for Norwegian participants

Early Bird Extended
Save EUR 100 when reserving your seat before 20th of September 10th of September

Public Source Code Access & Nightly Builds

by Jan Blomquist 24. March 2009 10:58

Can you close your eyes and reel off the 12 points to better code. Do you have the Joel's test fresh in mind? The Joel Test: 12 Steps to Better Code is extremly important for all software developers. In this blog we will cover the three first rules and how we have solved this in Gaiaware.




  1. Do you use source control?
  2. Can you make a build in one step?
  3. Do you make daily builds?

Do you use source control?

We couldn't imagine a life without source control. In fact several studies show that firms without a good source control system cannot survive (ref; http://www.stevemcconnell.com/rd.htm ). For all software development at Gaiaware we are currently using Subversion.

Because we also truly believe in open development of our library we have decided to publish the SVN repositories for public access. That means you can just add Gaia Ajax source directly to your solution (via externals ) and benefit from the rapid development of Gaia Ajax

Here's the urls for the repositories of Gaia Ajax

Tagged versions of Gaia Ajax (Released and archived)
Note! Use anonymous as username when asked for credentials

Can you make a build in one step?

Yes we can. We've built a customized build system that suits Gaia Ajax just perfectly. It's written in Ruby and uses Rake and COM interop to work with Visual Studio.NET. With Ruby's duck typing it's easy to read project properties, project items and different configuration settings. The build itself is also done with VS.NET using Ruby.

Do you make daily builds?

We've been making daily/nightly builds of Gaia Ajax for quite some time now and now we've finally decided to make them public.

The opening of the source and publishing of nightly builds allow you to post a bug/issue and have it fixed that very same day. Then you will have access to the bits within the next working day (even sooner if required). It should also be easy to pickup new bits that fit the requirements of your development. We will still post release dates for official relases which you can align with your project.

Nightly builds of the commerical package is available for commercialusers. If you have an active subscription just click on the nightlybuilds link to access the nightly builds.

Update 2009-06-29: You can test our nightly build samples here

Summary

Don't cheat when it comes to Joel's 12 steps to better code. Stability and base quality is key. What good does a piece of code do if it simply doesn't work. Source control and automated builds are just some the absolute requirements to achieve higher code quality. The importance of this was also pointed out in this blog post ->  ( Principles of UI architecture for libraries )

Enjoy the builds!  

Gaia Ajax 3.5 Released!

by Stian Solberg 4. March 2009 13:53
"Imagination is the beginning of creation. You imagine what you desire, you will what you imagine and at last you create what you will."
-George Bernard Shaw

Highlights of Gaia Ajax 3.5

Doubled Speed
Massive performance gains - up to 50% - in Ajax callbacks.



Zero ViewState
We've improved our internal ViewState logic.
For you: even less data sent, even faster applications!


20+ New Features And Enhancements
Built-in Default Skin, Multi File Upload, Better AspectKey, Improved Hybrid Control Collection ++ See list of new features and enhancements



60+ Bug Fixes
Thanks to feedback from our community and customers, over 60 bugs are fixed. Gaia is now even more stable! Complete change log 

  

Even More Stuff!

Improved Pricing

Take a look at our order page to see the new prices.

Take a quick survey - win a subscription license!

To constantly improve the quality of our deliverance we are conducting a quick survey. It takes two minutes, and all participating will have a chance to win a one year subscription of Gaia Ajax (value: $595) 
Take the survey here

Case Study: Logica

Logica is a leading IT and business services company, employing 40,000 people.
Read how they succeeded with Gaia 


Yes,one last thing: everyone can download the trial version. Go to http://gaiaware.net/download

As always, we love feedback. Use the comments or our the forum.

Best regards,

The Gaiaware Team.

Gaia and Ajax on Mobile Devices

by Jan Blomquist 25. February 2009 10:28

More and more Ajax Web applications are targeting the mobile browser. The age of dull and slow web experiences are long gone and the demand for high response and high interactivity on the mobile phone is here. At the end we present the 10 key tenets for building these next generation mobile web applications. 

Gaia Ajax on Mobile Devices in the Real World

Recently we delivered an Ajax Web Application with a Dual UI using templating techniques spiced with inspiration from Model View Presenter. The result was a single codebase with simple multi-device targeting. All built with open source technologies like Gaia Ajax, Castle ActiveRecord, Nhibernate, ZedGraph, NUnit and MySQL. And of course the solution worked nicely on Mono too :-)

We've tested Gaia Ajax on the following devices

All of them worked nicely with Gaia Ajax, except a few customizations for Opera Mobile. Let's have a look at how you can enable Gaia Ajax for this wonderful browser too, which by coincidence happens to be developed here in Norway too.

Fix for Opera Mobile

We use Prototype.js under the hood on the client side and unfortunately there's a small bug in Prototype that makes the Ajax engine break down on Opera Mobile. There are two ways to work around this problem.

  1. Embed the code snippet below somewhere on your ASP.NET page to override the Ajax.Request prototype implementation.
  2. Overwrite prototype.js in the Gaia.WebWidgets project and rebuild.

Code

   1:  <script type="text/javascript">
   2:      Element.observe(window, 'load', function() {
   3:          Ajax.Request.prototype.initialize = function(url, options) {
   4:              this.options = {
   5:                  method:       'post',
   6:                  asynchronous: true,
   7:                  contentType:  'application/x-www-form-urlencoded',
   8:                  encoding:     'UTF-8',
   9:                  parameters:   '',
  10:                  evalJSON:     true,
  11:                  evalJS:       true
  12:              };
  13:              Object.extend(this.options, options || { });
  14:   
  15:              this.options.method = this.options.method.toLowerCase();
  16:              if (Object.isString(this.options.parameters))
  17:                  this.options.parameters = this.options.parameters.toQueryParams();
  18:              else if (Object.isHash(this.options.parameters))
  19:                  this.options.parameters = this.options.parameters.toObject();
  20:              
  21:              this.transport = Ajax.getTransport();
  22:              this.request(url);
  23:          }
  24:      });
  25:  </script>

It's worth mentioning that this patch is only valid for Gaia Ajax since we know what we use.

Note! This is not a patch that should be applied to Prototype.js overall.  

Another 10 Key Reasons to use Gaia Ajax for Mobile Web Development

  1. Unified codebase
  2. Multi device targeting for broad reach
  3. No need to expose biz logic to client
  4. Single point of deployment
  5. Based on open standards
  6. Write applications in managed code (C#, VB.NET, Ruby.NET, IronPython, etc)
  7. No sync issues
  8. Minimal maintenance costs
  9. Rich user experience without the need for javascript
  10. No security hazards/breaches
Don't surrender to binary code distributions, but embrace open standards.

Adding a ConfigurationSection to your Gaia WebSite

by Jan Blomquist 17. February 2009 14:04

Now you can configure Gaia Ajax both programmatically in C# and through Web.Config. We've introduced our custom ConfigurationSection so that you can modify the behaviour of Gaia more easily.

 The first thing you need to do is define the custom ConfigurationSection in web.config. If you want to read more about .NET ConfigurationSections click here for the MSDN documentation on the subject.

   1:  <configSections>
   2:      <section 
   3:      name="GaiaAjaxSection"
   4:      type="Gaia.WebWidgets.GaiaAjaxConfigurationSection"
   5:      restartOnExternalChanges="true">
   6:      </section>
   7:  </configSections>
The next thing you can do is go ahead and implement the configuration section and set the properties you want.
   1:  <GaiaAjaxSection
   2:      EnableDefaultTheme="false"
   3:      EnableJavaScriptInclusion="true"
   4:      EnableDynamicScriptLoading="false"
   5:      EnableNestedCssClasses="true">
   6:  </GaiaAjaxSection>

So what exactly does these options do? Let's have a look at the different property settings and the consequences of implementing them.

1. EnableDefaultTheme

Gaia Ajax offers default theme capabilities so that if you haven't defined a CssClass and imported a style sheet, you will get some basic UI for your controls. Here's an example of Window, Button and Calendar with default themes. If you explicitly set the CssClass either directly or by using Themes or StyleSheetTheme, then the default theme will not be applied.

2. EnableJavaScriptInclusion

Gaia Ajax automatically embeds all required javascript, but if you prefer to manually include the javascript files you can turn off this setting. Reasons for turning it off could be

  • You have done custom concatentation/changes of the javascript files
  • You are hosting the javascript files on a remote / cache server
  • You want to have direct references instead of the cryptic references

3. EnableNestedCssClasses

All Advanced Gaia Ajax controls are rendered with a set of nested html elements that have defined unique css classes. This greatly simplifies skinning and we've tried to base the document layout according to best practices. If you don't like our suggested cssclass definitions and would like to override it with your own behaviour you can set this property to false. Output with nested css classes looks like this ...
   1:  <div class="default-window" id="Div1">
   2:      <div class="default-window-tl" id="Window1_header">
   3:          <div class="default-window-tr">
   4:              <div class="default-window-tc">
   5:              </div>
   6:          </div>
   7:      </div>
   8:      <div style="overflow: hidden;" class="default-window-contentwrapper">
   9:          <div class="default-window-ml" id="Window1_middle">
  10:              <div class="default-window-mr">
  11:                  <div class="default-window-mc">
Output without nested css classes looks like this ...
   1:   <div class="default" id="Div1">
   2:              <div id="Window1_header">
   3:                  <div>
   4:                      <div>
   5:                      </div>
   6:                  </div>
   7:              </div>
   8:              <div style="overflow: hidden;">
   9:                  <div id="Window1_middle">
  10:                      <div>
  11:                          <div>

4. EnableDynamicScriptLoading

Gaia Ajax has the option of automatically loading required javascript files on-demand in ajax callbacks. This feature is now turned off by default. Gaia Ajax 3.5 will automatically embed all javascript in one single file and include that file. If you still want to enable the dynamic script loading capabilities you can turn this feature on. Great, hopefully you see that custom configuration sections simplify configuration of your ASP.NET / Gaia Ajax application. 

Here's an example of how dynamic script inclusion looks like in FireBug

If you want to programmatically changes these values you can access them through code. Just access the singleton instance on GaiaAjaxConfiguration and set the properties yourself. These features are just some of the goodies coming up in Gaia Ajax 3.5.

Smarter HybridControl Collections in Gaia Ajax 3.5

by Jan Blomquist 15. February 2009 21:30

 

When building reusable server controls we have a plethora of different ways to build them. There are pros and cons to every solution and finding the best approach is not always easy. In Gaia Ajax 3.0 we introduced the HybridControl which is a combination of a composite control and a container control. That means we add some of our own controls and aspects to the control in addition to the controls the developer adds. Since we haven't seen this pattern (please correct us if we are wrong) we named the pattern HybridComposition.

Some examples of HybridControls include

  • Window
  • ExtendedPanel
  • TreeView
  • Toolbar 

The immediate benefit of the HybridControl is that you can directly add child controls in design time, markup and runtime. In runtime you get simple access to the controls just by typing in their name or accessing them through the controls collection.

   1:  Window1.Controls.Add(new LiteralControl("Hello Gaia Developers")); 

Issues

There were however some issues we encountered with this approach. Here are just some of the problems and you probably encountered one or more of them.

  1. The Controls collection wasn't fully yours anymore. It was mixed, partially ours, partially yours. That means a Controls.Clear() would destroy the HybridControl because the composite controls would be removed aswell.
  2. ForceAnUpdate implementation would get in the way of property serialization. That means when you tried to re-render for example the Window, the Caption would be left untouched even if you changed it, because partial rendering would overrule serialization.
  3. In some controls like the TreeView where you want to access both TreeViewItems and your custom controls, there were no clear separation of what belonged where. Effectively you ended up searching the Controls collection and filtering out stuff manually.

Solution

We've created specialized Control Collections and Collection wrappers in Gaia Ajax 3.5 to offer a clean and intuitive solution to the above problems. Since we cannot touch the Controls collection itself because ASP.NET heavily relies on it, we have chosen an approach were we sit on top of the existing collection and offer specalized behaviour on a pr/hybridcontrol basis. This generic wrapper is the foundation for all the other collections.

   1:  public abstract class ControlCollectionWrapper<T> : ICollection<T> where T : Control {}
The most important function that sits here is the IsValidControl(). For each control in the collection, derived collections can implemented this function to verify if the current control is valid in the collectionwrapper or not.
   1:  protected abstract bool IsValidControl(Control control);
For example in HybridPanelBase, the ancestor of Window we use the HybridControlCollection which is implemented like this
   1:  public class HybridControlCollection<T> : ControlCollectionWrapper<T> where T : Control
   2:  {
   3:      private readonly ICollection<Control> _skipTheseControls;
   4:      
   5:      public HybridControlCollection(T ownerControl, ICollection<Control> skipTheseControls) 
   6:      : base(ownerControl)
   7:      {
   8:          _skipTheseControls = skipTheseControls;
   9:      }
  10:   
  11:      protected override bool IsValidControl(Control control)
  12:      {
  13:          return !_skipTheseControls.Contains(control);
  14:      }
  15:  }

Based on the ControlCollectionWrapper we've currently created the following derived collections.

  • ControlCollectionExcept
  • ControlCollectionOf
  • HybridControlCollection

On the Window we define two collections, one is for the composition controls and the other is for the normal childcontrols. The signatures are as follows

   1:  protected internal ICollection<Control> CompositionControls {get;}
   2:  public virtual HybridControlCollection<Control> ChildControls {get;}

Usage

With this approach you will always have access to all your custom childcontrols in the ChildControls collection wrapper. The following operations which was considered hazardious in the 3.0 release is now safe and correct.

   1:  Window.ChildControls.Clear();
   2:  Window.ChildControls.InsertAt(0, new Control()); 
   3:  Window.ChildControls.RemoveAt(0);
Let's move over to the TreeView. The TreeView contains TreeViewItems which can be made up of more TreeViewItems or custom controls. Here we use both the ControlCollectionOf and ControlCollectionExcept to offer ways to manipulate both the Child TreeViewItems and custom ChildControls. The collections are implemented as follows
   1:  public ControlCollectionOf<TreeViewItem> TreeViewItems { get;}
   2:  public ControlCollectionExcept<TreeViewItem> ChildControls { get;}

It basically means the first collection is made of TreeViewItems, whereas the other collection is made up of anything, but TreeViewItems. Because we now have these collections on the TreeView, we suddenly have the same flexibility on the TreeView if we want to

  • Modify the TreeViewItems collection and perform now supported operations like Clear(), InsertAt(), RemoveAt(), etc.
  • Add custom ChildControls without having to deal with the TreeViewItems which are also in the collection.
  • It greatly simplifies ForceUpdate() scenarios since you have greater control over what you want to have re-rendered and not. We also have a few more control collections in Gaia Ajax 3.5, including the GenericControlCollection and AspectCollection.
We really hope you appreciate the research and development we are doing in this HybridControl space and we'd love to have your feedback on it. Dino Esposito reacted by saying "Wow! This is much better". We hope you think the same. 

Tags: , ,

Ajax | Gaia

Easily create Drag & Drop dashboards in ASP.NET

by Jan Blomquist 5. February 2009 10:20