Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Creating RIA with ASP.NET/Gaia AJAX/Flex combo

4.38/5 (6 votes)
23 Jul 2009GPL35 min read 32.8K   518  
An ASP.NET server control, a small Flex library, and a simple development pattern for integrating Flex components into ASPX.

Introduction

In this article, I would like to introduce the FlexContainer project – a simple way to integrate Flex components into ASP.NET pages developed with Gaiaware.

But first, if you are not familiar with Gaia AJAX – an excellent Open-Source AJAX enabler for ASP.NET, I would suggest visiting their site and reading an article by Dino Esposito, Where’s the Right Way to AJAX?, where he explains the essence of AJAX in general and the Gaiaware approach in particular.

Now, suppose you want to achieve the following:

  1. Have a classical ASP.NET development model, where you prefer to stick to server-side programming for controlling your presentation layer state and behavior, avoiding unnecessary client-side coding or bringing another piece into your ever growing technology stack.
  2. Extend your ASP.NET pages with various Flex components (e.g.. data visualization, graphing, imaging), but treat them as regular ASP.NET server controls.
  3. Have your Flex components respond to ASP.NET events (like other ASP.NET controls do) in an AJAX way.
  4. Have your ASP.NET respond to Flex events also in an AJAX way.
  5. Be able to bundle all or some of your flex components into a single SWF – creating a “Flex control library” so to speak, thus optimizing pages load/caching.
  6. Avoid using Flex server integration solutions such as WebORB or FluorineFX altogether with developing specialized services, RTMPT/RTMP tunneling, configuration, licensing and deployment quirks.

In other words, this is about having an AJAX ASP.NET application designed in the most intuitive way (covered by Gaia AJAX), but with Flex components embedded into pages and with full support of user interactions and AJAX messaging between .NET and Flex (covered by FlexContainer).

FlexContainer

FlexContainer consist of two pieces – a Gaia based server control (Ria.Web.Controls.dll) and a simple AJAX messaging wrapper library for Flex (FlexContainer.swc).

On a .NET side, the FlexContainer control embeds Flex into a page and serves as a communication medium between Flex and .NET. And since it is a Gaia extended control, the entire client/server communication is fully AJAXified. Also, it serializes and deserializes your messages to and from JSON.

On a Flex side, the AJAX messaging wrapper is responsible for:

  1. dispatching ActionScript events when external calls from .NET come,
  2. making calls to .NET (typically in response to user action), and
  3. serializing/deserializing JSON to/from an AS3 Object.

If you want more info on the design, please visit the FlexContainer project page at http://flexcontainer.googlecode.com where I have posted some documentation.

Code Samples and Usage

ASP.NET

ASPX Page

The following creates a FlexContainer server control:

XML
<fc:FlexContainer
    ID="fcControlTwo"
    runat="server"
    FlexFile="Flex/FlexControls.swf"
    FlexState="controlTwo"
    InitialData="Hello from .NET (InitialData)"
    OnIncomingObjectEvent="fcIncomingObject"
    ShowFlashMenu="false"/> 
  • FlexState – optional attribute used for dealing with Flex libraries, where each Flex control has an associated state. When SWF is loaded, Flex will simply set the specified state loading the control (using Application.currentState).
  • InitialData – optional attribute which contains plain or JSON string. This is sent to the Flex control when it's first loaded in the browser. It can be used for data and/or state/behavior initialization of a Flex control.
  • OnIncomingObjectEvent – event handler for requests from Flex.

ASPX.CS Code Behind

The following code prepares a JSON string for initializing a Flex control. Here, the GetControlOneInitialData() method returns a string with a complex JSON object:

C#
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
        fcControlOne.InitialData = 
                DemoDataServices.GetControlOneInitialData();
}

The following handles events from FlexContainer. Note that data from Flex e.Data comes in as a JsonObject. Read more about it here: http://www.codeproject.com/KB/recipes/JSON.aspx.

C#
protected void fcIncomingObject(object sender, FlexContainer.IncomingObjectEventArgs e)
{
    if (e.Data["state"].Equals("controlOne"))
    {
        ajaxLabel.Text = string.Format("Name: {0} StartDate: {1} Age: {2}\n",
                         e.Data["name"], 
                         e.Data["startDate"], e.Data["age"]);
    }
    ...
}

This code sends JsonObject to a FlexContainer fcControlTwo in response to a button click event. Here, GetSayHello() returns the type JsonObject:

C#
protected void OnSayHelloButtonClicked(object sender, EventArgs e)
{
    fcControlTwo.FlexCallObject(DemoDataServices.GetSayHello());
}

Flex

Organizing the Flex control library

Here's the fragment of MXML that creates a "Flex control library". As you can see, each included control has an associated state name. On the .NET side, this name should be specified in the FlexContainer.FlexState attribute.

XML
<mx:states>
    <mx:State name="controlOne">
        <mx:AddChild>
            <control:ControlOne
                id="c1"
                creationComplete="onControlOneComplete(event)"/>
        </mx:AddChild>
    </mx:State>
    <mx:State name="controlTwo">
        <mx:AddChild>
            <control:ControlTwo
                id="c2"
                creationComplete="onControlTwoComplete(event)"/>
        </mx:AddChild>
    </mx:State>
</mx:states>

Flex Control Loading/Initializing

The following initializes an AJAX messaging wrapper and loads a control based on the provided FlexState:

C#
import flexcontainer.ajax.AjaxWrapper;
import flexcontainer.ajax.events.ExternalCallObjectEvent;

// ajax messaging/config wrapper
private var ajax:AjaxWrapper;

private function init():void {
    // create ajax messaging/config wrapper
    ajax = new AjaxWrapper(onAjaxCall, root.loaderInfo.parameters);

    // set application current state - "load" the needed control
    if(ajax.configuration.state != null)
        currentState = ajax.configuration.state;
}

The above method init() is invoked on applicationComplete. The AjaxWrapper constructor takes two arguments: an event handler for all the messages from AJAX (type function) and a root.loaderInfo.parameters required for reading the initial configuration/state of a particular instance of FlexContainer.

When the Flex control is loaded, we might want to initialize its data/state/behavior. Here's an example:

C#
private function onControlOneComplete(event:Event):void {
    // initialize grid data received from .NET
    var data:Object = ajax.configuration.initialData;
    c1.myLabel.text = data.someText;
    c1.myDataGrid.dataProvider = new ArrayCollection(data.people);

    // add event listener for item selection in grid
    c1.myDataGrid.addEventListener(ListEvent.ITEM_CLICK, onGridClick);
}

Note that ajax.configuration.initialData provides an Object type. In this example, it contains someText:String for myLabel initialization and people:Array for myDataGrid. In addition, this method adds an event listener for the control.

Sending and Receiving Messages

Here is an incoming AJAX messages dispatcher example. The event ExternalCallObjectEvent contains a data member of type Object (already deserialized):

C#
// all calls from .NET are dispatched here
private function onAjaxCall(event:ExternalCallObjectEvent):void {
    switch(event.data.state) {
        case "controlOne":
            controlOneActions(event.data);
            break;
        case "controlTwo":
            ...;
    }
}

To send a message to .NET, the AjaxWrapper.callToAjax() method is used. In the example below, the message data is constructed from the current selection in a grid. This call eventually gets handled in .NET as shown above (see the fcIncomingObject sample in the ASPX.CS section).

C#
// send data object to .NET on grid selection
private function onGridClick(event:ListEvent):void {
    var data:Object = new Object();
    data.name = event.currentTarget.selectedItem.name;
    data.startDate = event.currentTarget.selectedItem.startDate;
    data.age = event.currentTarget.selectedItem.age;
    ajax.callToAjax(data, currentState);
}

Building/Running the Demo Project

Download FlexContainer.zip from this page or project page, extract to a new folder. The folder .\bin contains the compiled FlexContainer server control, the AJAX Messaging Wrapper ActionScript library, and other required assemblies:

  • FlexContainer server control: .\bin\FlexContainer\Release\Ria.Web.Controls.dll
  • AJAX ActionScript library: .\bin\FlexContainer\FlexContainer.swc
  • Other assemblies: .\bin\*.dll

To run the demo on localhost, simply open .\demo\demoApplication.sln with Visual Studio 2008 and hit Ctrl-F5. All required assemblies are bundled with the demo and referenced from the .\bin folder.

The source code is currently available from the project SVN repository.

Conclusion

I hope some of you will find the described approach useful for your projects. Please note that I will be updating FlexContainer in the project's site at http://flexcontainer.googlecode.com.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)