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:
- 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.
- Extend your ASP.NET pages with various Flex components (e.g.. data visualization, graphing, imaging), but treat them as regular ASP.NET server controls.
- Have your Flex components respond to ASP.NET events (like other ASP.NET controls do) in an AJAX way.
- Have your ASP.NET respond to Flex events also in an AJAX way.
- 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.
- 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:
- dispatching ActionScript events when external calls from .NET come,
- making calls to .NET (typically in response to user action), and
- 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:
<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:
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.
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
:
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.
<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
:
import flexcontainer.ajax.AjaxWrapper;
import flexcontainer.ajax.events.ExternalCallObjectEvent;
private var ajax:AjaxWrapper;
private function init():void {
ajax = new AjaxWrapper(onAjaxCall, root.loaderInfo.parameters);
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:
private function onControlOneComplete(event:Event):void {
var data:Object = ajax.configuration.initialData;
c1.myLabel.text = data.someText;
c1.myDataGrid.dataProvider = new ArrayCollection(data.people);
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):
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).
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.