Gaia Ajax 4.0 is in the nightly!

by Stian Solberg 18. June 2013 11:03

Gaia Ajax 4.0We have been spending a lot of time the last months wrapping up what will be the upcoming 4.0-release.

It is easy to grab the latest bits:

To get a summary of what has changed, take a look at front page of nightly samples.

We'd love to get your feedback, please use the forum.

Kind regards
The Gaiaware team

 

 

Gaiaware is a Microsoft Silver Partner

by Stian Solberg 14. August 2012 12:05

We're happy to announce that Microsoft have granted us the status as a Silver Independent Software Vendor (ISV). For us, this is a nice reflection of our ongoing efforts of building a high quality software tool like Gaia Ajax. The proven result for our customers is increased productivity and quality when building complex web applications on the Microsoft stack. The partnership is based on positive feedback from customers with successful web applications developed using Gaia Ajax.

Gaia Ajax 3.7 Release Notes

by Jan Blomquist 15. June 2011 01:06
Gaia Ajax 3.7 release notes ...

It's a great pleasure to announce the availability of Gaia Ajax 3.7. A premier GUI library for ASP.NET 2.0, 3.5 & 4.0 with sophisticated built-in ajax support. At it's foundation is the embracing of the ASP.NET programming model with server controls, events and the .NET programming model.

Instead of claiming that it's the finest ajax library for ASP.NET, perhaps you should give it a spin yourself

Why should I upgrade to Gaia 3.7?

  •  Visual Studio 2010: We now fully support VS.NET 2005, 2008 and 2010!
  •  Ajax: All controls now fully utilize the advanced ajax engine
  •  Features: Lots of new and exciting features in controls and aspects
  •  Samples: New samples available - experience the highlights at the online samples

How does Gaia Ajax assist with Web Development in ASP.NET?

  • 40+ ajax server controls (window, treeview, tabcontrol, etc)
  • 10+ aspects to add behaviours (drag&drop, modality, resizable) to all controls.
  • 20+ effects to easily add animations to all controls
  • Build the entire Web App fully in your favorite .NET language
  • Browsers: IE6,7,8,9, FireFox, Safari, Opera, Chrome, ...
  • Source code included
  • Royalty-free

Did you know that?

  • Gaia Ajax is enjoyed by millions of end users all around the world
  • Gaia Ajax 1.0 was first released 5th of February 2007.
  • Gaiaware is the name of the company behind Gaia Ajax
  • Gaiaware's chairman, Eirik Chambe-Eng, was one of the two founders of QT

What are you waiting for ...

Click here to see the full changelog for Gaia Ajax 3.7

Gaia Ajax 3.7 (Release ChangeLog)

by Jan Blomquist 14. June 2011 20:56

 

Issue Summary Resolution Desc.
GAIA-250  

Modality issue with Opera 

Complete
GAIA-253  

Window Height and Width issue 

Complete
GAIA-255  

Visibility change issues 

Complete
GAIA-272  

Cannot set TabView to be Visible False 

Complete
GAIA-281  

Menu icons clicking issue 

Complete
GAIA-288  

Window is hiding other controls 

Complete
GAIA-322  

Window visibility change performance issue 

Complete
GAIA-342  

Designer references in GPL build 

Complete
GAIA-343  

AspectKey Esc doesn't work in FireFox 

Complete
GAIA-364  

TabControl properties unchangable during callbacks 

Complete
GAIA-376  

Not possible to set TextMode during Ajax callback 

Complete
GAIA-380  

Cannot switch SingleLine = true | false in Ajax callbacks 

Complete
GAIA-381  

Cannot switch HasButtons = true | false in Ajax callbacks 

Complete
GAIA-382  

Cannot set MouseClicksToTriggerEditMode in Ajax callbacks 

Complete
GAIA-383  

Cannon set dtp.Value = null; 

Complete
GAIA-386  

Can't set Text property with apostrophe in callback 

Complete
GAIA-390  

Slider cannot be set without width 

Complete
GAIA-392  

Set MM/dd/yyyy HH:mm as DefaultValue for format 

Complete
GAIA-406  

No TabIndex property on DateTimePicker 

Complete
GAIA-413  

Slider doesn't serialize Aspects 

Complete
GAIA-42  

Gaia doesn't support EncryptedViewstate properly or callback validation in ASP.NET 

Complete
GAIA-103  

Gaia fails when compression is enabled. 

Complete
GAIA-112  

ASP.NET TextBox compatibility issue 

Complete
GAIA-139  

Highlight Effect changes element background 

Complete
GAIA-143  

Compatibility issue 

Complete
GAIA-417  

Callback text formatting issue 

Complete
GAIA-418  

Window centering issue 

Complete
GAIA-420  

Exception with enabled Trace 

Complete
GAIA-422  

AspectResizable cursor issue 

Complete
GAIA-424  

AutoCompleter ScrollBar click issue 

Complete
GAIA-425  

GridView CommandField exception 

Complete
GAIA-426  

ID handling conflict 

Complete
GAIA-429  

InPlaceEdit empty content issue 

Complete
GAIA-430  

AspectResizable issue with paddings 

Complete
GAIA-435  

DRIMR compatibility issue 

Complete
GAIA-436  

OnClientClick formatting issue 

Complete
GAIA-438  

Dynamic TreeViewItem issue 

Complete
GAIA-439  

Window click handling issues 

Complete
GAIA-440  

DRIMR issue related to control re-rendering detection 

Complete
GAIA-441  

Opera scrolling regressions 

Complete
GAIA-442  

Window BringToFront issues 

Complete
GAIA-446  

DRIMR issue related to control renaming and visibility change 

Complete
GAIA-451  

DRIMR issues related to hidden controls 

Complete
GAIA-452  

TableCell wrapping issue 

Complete
GAIA-453  

GridView ForceAnUpdate issue 

Complete
GAIA-454  

Cannot call .Focus() on AutoCompleter 

Complete
GAIA-455  

Error in rebinding with extra rows when ShowFooter="true" in GridView 

Complete
GAIA-456  

EmptyDataText does not work 

Complete
GAIA-457  

Datetimepicker calandar opens when enter/return key is hit in a textbox on the same form/page 

Complete
GAIA-458  

Make it possible to add validators to InPlaceEdit 

Complete
GAIA-460  

Name attribute for the generated a tag contains "$" 

Duplicate
GAIA-462  

Cannot have a RequiredFieldValidator in a EditItemTemplate in a GridView 

Complete
GAIA-467  

Failed to load viewstate error when using DateTimePicker where the master page have a Gaia Panel 

Complete
GAIA-472  

Method dispatching issue 

Complete
GAIA-473  

Issue with hidden RegularExpressionValidator in Mono. 

Complete
GAIA-474  

Js TypeError: element is null when using EditItemTemplate with DateTimePicker in GridView 

Complete
GAIA-476  

Any validator in GridView EditItemTemplate gives null reference exception 

Complete
GAIA-477  

AspectKey issue 

Complete
GAIA-479  

DaterTimePicker Dynamically Added To An ExtendedPanel on Mono 

Complete
GAIA-432  

Javascript response formatting issue 

Complete
GAIA-444  

DRIMR issue related to control removals 

Complete
GAIA-486  

Click event bubbling issue in extension controls 

Won't Fix
GAIA-487  

Button controls event bubbling issues 

Complete
GAIA-492  

Remove default text "Window" in caption of Window 

Complete
GAIA-497  

Tracing in ASP.NET seems to be broken 

Complete
GAIA-499  

Cannot have an ampersand in text in ListBox 

Complete
GAIA-504  

Issue with AspectResizable in Webkit browsers 

Complete
GAIA-505  

Cross site scripting issue with Gaia.Control._defaultUrl 

Complete
GAIA-506  

InPlaceEdit - Cancel button is not implemented correctly 

Complete
GAIA-502  

Performance issues in TreeView 

Complete
GAIA-483  

LinkButton markup validation 

Complete
GAIA-498  

Prototype and script.aculo.us upgrade 

Complete
GAIA-445  

Callback evaluation responsiveness enhacements 

Complete
GAIA-463  

Add gaia:TemplateField to GridView 

Complete
GAIA-443  

Container related performance enhancements 

Complete
GAIA-431  

AspectResizable and AspectDraggable compatibility enhancement 

Complete
GAIA-187  

TreeViewItems traverses recursively to get TreeView 

Complete
GAIA-230  

InPlaceEdit textbox content formatting 

Complete
GAIA-234  

Null CssClass property issue 

Complete
GAIA-299  

Expose SelectAll method for textbox of AutoCompleter 

Complete
GAIA-314  

AspectKey SetKeyListeners enhacement 

Complete
GAIA-416  

GridViewRow can have Aspects attached 

Complete
GAIA-423  

Snapping support in AspectResizable 

Complete
GAIA-421  

Snapping support in AspectDraggable 

Complete
GAIA-178  

ResetTimer() method 

Complete
GAIA-433  

Cancellable events support for Resizable, Draggable and Droppable aspects 

Complete
GAIA-434  

Bounding rectangle support in AspectResizable 

Complete
GAIA-480  

Reset() function on Timer 

Complete
GAIA-481  

BeginDrag event on AspectDraggable 

Complete
GAIA-482  

Added support for knowing if Draggable actually hit Droppable 

Complete
GAIA-491  

Remove global css styles 

Unresolved

Official release blog for Gaia Ajax 3.7

GWF beta released! (w/full source) - a unique approach to web application development

by Jan Blomquist 28. December 2010 17:25

GWF was created for the following reasons

  1. To simplify web application development with built-in support for many of the tasks we do over and over again
  2. To serve as a more complete example of what can be accomplished with Gaia Ajax - the best ajax library for ASP.NET!
  3. To illustrate the powerful DRIMR technology with a concrete example of it's benefits

GWF had the following design goals in mind

  1. Document based storage approach (JSON)
  2. Drag&Drop page composition with instant loading
  3. Use Convention over Configuration
  4. Dynamic Discovery of resources and definitions
  5. Simple and convenient API for developers
  6. Easy to extend
  7. Also licensed under GPL

Click here to download gwf-beta1-src.zip (VS.NET 2010 SLN)

The GWF package also includes

  1. Gaia Server Control Wrapper for TinyMCE rich-text-editor
  2. Gaia EntityView controls w/validation support

GWF is not

  1. A fully fledged CMS (yet!) or AMS for that matter
  2. Fully documented
  3. Fully tested

Use GWF if you want

  1. To get some useful bits of code for your web application
  2. To be inspired by the no-javascript approach of Gaia Ajax
  3. A convenient ajax based page navigation with full browser history support
  4. A modular approach to your web applications
  5. A code-less, create more strategy
  6. To create a nice KPI dashboard solution with content reuse via DRIMR
  7. To create an AJAX based wizard
  8. A dynamic UserControl loading framework
  9. More of your dreams to come true :-)

Click here to download gwf-beta1-src.zip (VS.NET 2010 SLN)

Now let's discuss some of the goodies in GWF:

GWF uses a document-based approach to define Pages. As you can see there's a one-to-one mapping between the navigation in GWF and the document folder structure on the disk. Also each page in GWF is called a VirtualPage because modules can be dynamically added, removed and reused between page navigations. Yes -You read me right! The powerful DRIMR technology in Gaia Ajax is able to dynamically insert and remove modules and also reuse data based on the coordinate system.

VirtualPage composition is fully WYSIWYG, but you can also just edit/xcopy the files directly if you need to modify each page (VirtualPage). An example of such a document can be seen in the screenshot below.

 

If you have missed a RichTextEditor in Gaia Ajax you can use the editor provided in GWF which is a wrapper around TinyMCE

Creating "Modules" in GWF is as simple as just creating a UserControl (no inheritance requirements imposed on you). In the screenshot below you can see the YouTube module created in ~30 lines of code. When VideoUrl is tagged as ModuleSetting, an editor in Edit mode is automatically provided for you. Also this value is persisted automatically in the document based file automatically.

 

Another nice treat is that "new" modules are automatically discovered and will appear in the AvailableModules list. That means zero configuration!

By now you probably wonder how things are composed. Let's walk through the rules / functional stuff

  1. You can create a hierarchy of VirtualPages and use ajax page based navigation between them
  2. Each VirtualPage requires a Layout which is basically the container controls where Modules can be dropped and configured
  3. Each Module can have a Container which is the chrome around it. The Container can be turned off, but will always be visible in edit mode to enable the editors
  4. Each Module can opt-in for loading and saving of ModuleSettings.
  5. Each Module can opt-in for additional EditorCommands. (see RichTextEditor / ISupportCommands)
  6. Use GwfManager.Instance.VirtualRedirect(string) to perform virtual page redirects (tip: check Firebug response :-) )
  7. Use the building blocks to define your own desired behavior. The Website/default.aspx is just an example to demonstrate some of the capabilities in GWF

Click here to want a small YouTube video demonstrating GWF

GWF has been used successfully in a few customer projects. Feel free to take it for a spin yourself! Contributions/Forks are welcome.

 

 

Using Flickr API with ASP.NET, Gaia Ajax and JSON

by Kariem 4. December 2010 00:39

As we go through this simple tutorial you will be introduced to some of the features of the Gaia Ajax Framework. This tutorial is ideal for those who are new to Gaia. We will build a simple app that searches for images with a specific tag on Flickr, reads and parses the JSON response and loads the images on the page.

Search Flickr

Setting The Stage

You can start with a regular ASP.NET Website (or web project) and add references to the Gaia dlls. We just announced a public beta release of Gaia Ajax 3.7, you can read about it and download the dlls and smaples from there. Then register the Gaia Controls either at the page level:

   1:  <%@ Register 
   2:      Assembly="Gaia.WebWidgets" 
   3:      Namespace="Gaia.WebWidgets"
   4:      TagPrefix="gaia" %>
   5:   
   6:  <%@ Register 
   7:      Assembly="Gaia.WebWidgets.Extensions"
   8:      Namespace="Gaia.WebWidgets.Extensions" 
   9:      TagPrefix="gaia" %>

 

or globally for your entire app in web.config:

   1:  <system.web>
   2:   <pages>
   3:     <controls>
   4:       <add assembly="Gaia.WebWidgets" 
   5:            namespace="Gaia.WebWidgets" 
   6:            tagPrefix="gaia" />
   7:       <add assembly="Gaia.WebWidgets.Extensions"     
   8:            namespace="Gaia.WebWidgets.Extensions" 
   9:            tagPrefix="gaia" />
  10:     </controls>
  11:   </pages>
  12:  </system.web>


Gaia Controls

After that we will add a Gaia TextBox, Gaia Button and a Gaia Panel to the page: 

   1:  <gaia:TextBox runat="server" ID="searchFlickrTextBox" />
   2:  <gaia:Button 
   3:        runat="server" 
   4:        ID="searchFlickrButton" 
   5:        Text="Search Flickr" 
   6:        OnClick="searchFlickrButton_Click" />
   7:  <gaia:Panel 
   8:        runat="server" 
   9:        ID="flickrPhotosPanel" 
  10:        CssClass="flickr-images-container" /> 

 

These Gaia controls extend their ASP.NET counterparts to give you Ajax functionality out-of-the-box. We will use the Gaia Panel as a container for the images we will load on the page. By handling the Click event of the Gaia Button we can start to write the functionality.

We use the Property SearchTag to store the search text entered by the user in the ViewState. Then we clear the Controls collection of the container Panel and call LoadFlickrImages:

   1:  protected void searchFlickrButton_Click(object sender, EventArgs e)
   2:  {
   3:      SearchTag = searchFlickrTextBox.Text;
   4:      flickrPhotosPanel.Controls.Clear();
   5:      LoadFlickrImages();
   6:  }

 

We need to store some information in the ViewState in order to recreate the images on subsequent postbacks. Since we will add the images dynamically to the page, it is our responsibility (not ASP.NET's) to keep them "alive" between postbacks. We need to persist the search tag and the list of images and in Page_Load we can recreate the Image controls on each postback by calling LoadFlickrImages:

 

   1:  private List<FlickrImage> Images
   2:  {
   3:      get
   4:      {
   5:          if (ViewState["images"] == null)
   6:              ViewState["images"] = new List<FlickrImage>();
   7:          return (List<FlickrImage>) ViewState["images"];
   8:      }
   9:  }
  10:   
  11:  private string SearchTag
  12:  {
  13:      get { return (string)(ViewState["searchtag"] ?? string.Empty); }
  14:      set { ViewState["searchtag"] = value; }
  15:  }
  16:   
  17:  protected void Page_Load(object sender, EventArgs e)
  18:  {
  19:      if (IsPostBack && !string.IsNullOrEmpty(SearchTag) && Images.Count > 0)
  20:          LoadFlickrImages();
  21:  }

 

The LoadFlickrImages method is where the magic happens, so let's dive into it.

 

Communicating With Flickr

We start by calling another method, GetResponseJsonString, to ummm, get the response JSON string Smile.

   1:  var jsonString = GetResponseJsonString();

 

So let's look into that method first. We start by creating a Post HttpWebRequest object to communicate with the Flickr service:

   1:  var webRequest = (HttpWebRequest)WebRequest
   2:      .Create(string.Format(FlickrServiceUrl, SearchTag));
   3:     webRequest.Method = "POST";
   4:     webRequest.KeepAlive = false;

 

The service URL looks like this:

"http://api.flickr.com/services/feeds/photos_public.gne?tags={0}&tagmode=any&format=json&jsoncallback=%3F"

For a provided tag this would return JSON similar to the following:

   1:  ({
   2:   "title": "...",
   3:   "link": "...",
   4:   ...
   5:   "items": [
   6:      {
   7:         "title": "...",
   8:         "link": "...",
   9:         "media": {"m":"..."},
  10:         ... 
  11:      },
  12:      {
  13:         "title": "...",
  14:         "link": "...",
  15:         "media": {"m":"..."},
  16:         ... 
  17:      },
  18:      ...
  19:   ]
  20:  })

 

Then we will read the response stream into a string:

   1:  string jsonString;
   2:  using (var flickrResponse = webRequest.GetResponse() as HttpWebResponse)
   3:  {
   4:       if (flickrResponse == null)
   5:           return string.Empty;
   6:       // Get the response stream to read the response
   7:       using (var responseStream = flickrResponse.GetResponseStream())
   8:       {
   9:           if (responseStream == null)
  10:               return string.Empty;
  11:           // Read the response
  12:           using (var reader = new StreamReader(responseStream))
  13:           {
  14:               jsonString = reader.ReadToEnd();
  15:           }
  16:       }
  17:  }

 

Notice that the returned JSON above is wrapped in parentheses, so we need to remove those and return the JSON string back to the caller, LoadFlickrImages:

   1:  jsonString = jsonString.Remove(jsonString.IndexOf("("), 1);
   2:  return jsonString.Remove(jsonString.LastIndexOf(")"), 1);

 

Back in LoadFlickrImages we parse the returned JSON string using JSON.NET:

   1:  var responseJson = JObject.Parse(jsonString);

 

Then using linq to JSON, also part of JSON.NET, we can extract the useful information we want about each Image. For example here we extract the Title, the URL of the image's page on Flickr (Link) and the URL of the actual image thumbnail (Media).

 

   1:  var images = from item in responseJson["items"].Children()
   2:               select new FlickrImage 
   3:               {
   4:                   Title = (string)item["title"],
   5:                   Link = (string)item["link"],
   6:                   Media = (string)item["media"]["m"]
   7:               };

 

Then we need to update the generic list of images (List<FlickrImage>) that we keep in the ViewState:

   1:  Images.Clear();
   2:  Images.AddRange(images);

 

After that we can iterate over it and create a Gaia Image control for each one:

   1:  foreach (var image in Images)
   2:  {
   3:      var imageControl = new Image
   4:      {
   5:          ImageUrl = image.Media,
   6:          AlternateText = image.Title,
   7:          CssClass = "flickr-image"
   8:      };
   9:      imageControl.Aspects.Add(new AspectHoverable());
  10:      imageControl.Effects.Add(
  11:          AspectHoverable.EffectEventMouseOver, 
  12:          new EffectPulsate(1));
  13:   
  14:      flickrPhotosPanel.Controls.Add(imageControl);
  15:  }

 

Let's have a closer look at this code. Here we create the Gaia Image control and set its CssClass property. This CSS class "flickr-image" sets the margin style property on the images so that they would have a nice space between them when they are loaded on the page:

   1:  var imageControl = new Image
   2:  {
   3:      ImageUrl = image.Media,
   4:      AlternateText = image.Title,
   5:      CssClass = "flickr-image"
   6:  };

 

Then, we add a little effect that fires when the user hovers over the image:

   1:  imageControl.Aspects.Add(new AspectHoverable());
   2:  imageControl.Effects.Add(
   3:      AspectHoverable.EffectEventMouseOver, 
   4:      new EffectPulsate(1));


Aspects and Effects

This introduces us to two interesting features of Gaia, Aspects and Effects. Aspects are little pieces of functionality that you can add to Gaia controls. For example, if you need to make a Label clickable you can add an AspectClickable to its Aspects collection and this would give you a server-side event that you can handle when the Label is clicked. Effects are simply animations that you can apply on a Gaia control. 

 

   1:  imageControl.Aspects.Add(new AspectHoverable());

 

Here we are adding an AspectHoverable to the Image control. Doing this we have the opportunity to handle server-side events that fire when the user hovers over an image or away from it. In other words this way you can handle client-side events like OnMouseOver and OnMouseOut on the server using regular ASP.NET server-side events. This, of course, happens without needing to worry about client-side details or to write any Javascript. 

 

However, that is not the purpose behind adding AspectHoverable to the Image control. Looking at the other line we can see why:

   1:  imageControl.Effects.Add(
   2:      AspectHoverable.EffectEventMouseOver, 
   3:      new EffectPulsate(1));

 

We are adding an EffectPulsate to the Effects collection of the Image control. However, here we are also using what we call an effect event. These allow you to combine the use of both Aspects and Effects to have the Effects (which run on the client-side) fire in response to a client-side event like OnMouseOver in our case here. So unless you have explicitly chosen to handle server-side events for AspectHoverable, this will be purely client-side. And the best part is that you are able to achieve this without writing any Javascript.

 

DRIMR

Then we add the Image control to the Gaia Panel that is used as a container for the images:

   1:  flickrPhotosPanel.Controls.Add(imageControl);

 

This brings us to one of the most intelligent features of Gaia, DRIMR. DRIMR almost eliminates the need for partial rendering. Usually here we would have needed to re-render the Panel and it's child controls (the images) to the client, since we have changed the Controls collection of the Panel. However, Gaia, with DRIMR, is smart enough to know that the client-side hierarchy almost doesn't change, so it will get re-used instead of being destroyed and rebuilt. You will specially notice this on the second time (and subsequent times) you use the app. You can almost see that the images are changing without the client-side hierarchy being destroyed and rebuilt. You don't need to worry about learning anything new or doing anything yourself to get this amazing benefit. If you are using Gaia, DRIMR is doing what it's supposed to behind the scenes.

 

Conclusion

As you can see using Gaia Ajax you can basically rely on the knowledge you already have about ASP.NET to automatically get Ajax functionality and much more. You are also able to tap into client-side events and handle them using regular server-side events and you can even have pure client-side Effects. All that can be achieved without writing any Javascript or worrying about any client-side details. 



Gaia Ajax 3.7 *beta*

by Jan Blomquist 22. November 2010 15:13

Highlights

  • VS.NET 2010 Support (Improved Design Time Experience)
  • DRIMR enhancements (All extensions now utilize DRIMR)
  • Compatibility with ASP.NET and 3rd party control libraries

Links

Gaia Ajax 3.7 beta is a solid product that probably could have been labeled a release. It's currently deployed to multiple large scale production applications and is running smooth and fast. We do however strongly believe in getting some bits out for public consumption before we do the final mark and make it an official release.

Since we believe so strongly in open standards we have continued to evolve and innovate on top of the ASP.NET platform. Gaia Ajax 3.7 is yet another proof that Gaiaware is committed to you as a long term partner that you can put some trust in. Also due to the nature of our dual license policy and inclusion of source code you are guaranteed the ability to modify and extend the product.

GWF - Gaia Web Framework Video Demo

If you want to learn more about the possibilties with Gaia Ajax -we recommend you watch the following video demonstrating the GWF framework which we will ship with the final version of Gaia Ajax 3.7. It nicely demonstrates the power of Gaia Ajax as the best toolset for building powerful web applications on top of ASP.NET.

Where to from here

The 3.7 beta download only contains the dlls -so we are considering various installation frameworks to create a good install experience before we go live with the 3.7 release. We will fix reported issues asap and make them available via our build servers. If you want to go in production with the 3.7 beta simply just buy the 3.6 version which entitles you to use the 3.7 bits. Smile

Tags: , , ,

Ajax | Gaia | Mono

We're delayed - 3.7 will come!

by Stian Solberg 1. July 2010 11:25

Waiting for Gaia Ajax 3.7? So do we!

Waiting for Gaia Ajax 3.7?

We decided to go some major rewritings which we should have done a long time ago; now we're doing it. Especially the extensions controls will have a better architecture. Additionally we're doing this to improve the Visual Studio 2010 experience, as it is related to the actual code in each control.

Regarding the nightly build server, we expect this to be up in a couple of weeks. We took it down because of the major changes in the core library.

We'd like to say we are very sorry for the broken promises, but we want to deliver solid software to our users; it costs quite an amount of hour for us to make you save even more development hours.

Best regards
The Gaiaware team: Sergey, Jan, Stian, Kariem and Espen

Update: The 3.7 BETA is finally here!

 

LinkedIn .NET User Group Online Presentation Tomorrow

by Stian Solberg 9. March 2010 22:54

We will hold an online, free presentation showing what you can do with Gaia Ajax when building next generation web applications in a fast, lightfoot and intelligent way. Jan Blomquist will demonstrate the power of our latest 3.6 version and why abstracting away JavaScript and developing in a managed language is crucial for time-to-market.

5 winners will be chosen at random from the list of attendees. Each of them will win an annual subscription of Gaia Ajax (worth $595).

Wednesday March 10, 2010, 11:00AM (PST)
Get local time

LIDNUG event info

Direct link to Live Meeting

 

 

 

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