This article is a document translated specifically for my partner to read; since it might help some folks, I’m also posting it for reference by anyone who needs it. If it doesn’t fit your situation though, I can’t take responsibility. Also, this article was exported directly from Word (page size A3), with way too much redundant code, and I can’t be bothered to clean it up; brothers with a display resolution width below 1280 may see misaligned styling when reading, so please bear with it.
Overview:
The FluorineFx open source library provides a set of features for the .NET framework, implementing FLEX/FLASH remoting, Flex Data Services and real-time messaging.
.NET frameworks supported by FluorineFx
Microsoft .NET Framework 1.1 (1.1.4322)
Microsoft .NET Framework 2.0 (2.0.50727)
Microsoft .NET Framework 3.5 (3.5.21022.8)
Mono 1.2.4
(.NET framework support is backward compatible)
Features
Flex, Flash Remoting (RPC)
Flex Messaging (partial)
Flex Data Services (partial)
Supports AMF0, AMF3 and RTMP protocols (we use this one)
Service Browser
Template based code generator (ASP.NET like syntax)
Easily integrate rich Internet applications with .NET backend
Easily integrate with Adobe Integrated Runtime (Adobe AIR™)
ASP.NET 2.0 Application Directory Layout
The physical structure of an ASP.NET 2.0 application is as follows:
(Only assemblies/types located under LAC (the bin directory) can be accessed by fluorineFX)
Deploying with Visual Studio
We more strongly recommend referring to the FLUORINEFX VISUAL STUDIO 2005 Wizard section to create a solution with fluorineFX enabled.
If you’d rather deploy a solution manually, the table below shows the minimum steps:
Create your project, or open an existing solution.
Use “Add Reference (R)…” to add the assemblies you need.

Or, if you plan to debug fluorineFX, add the FluorineFx-2.0.csproj you downloaded earlier to your solution, then use “Add Reference” and pick a project reference. (- - ! This guy’s English isn’t that standard either, he doesn’t like adding punctuation, just like when we chat online, which easily creates ambiguity)Add the following code to your Web.config file, inside the <system.web> node:
- Use “Add Web Form” to create an empty file Gateway.aspx. The gateway URL will point to this file.
FluorineFx Visual Studio 2005 Wizard
To make creating a fluorine-enabled ASP.NET easier, the Fluorine wizard lets you create a custom new project that’s already configured to work with the gateway. (mousebomb: the gateway here is implemented by Gateway.aspx; whether it’s a remoting server side or an RTMP server side, both communicate facing this gateway)
There are 2 project templates used to create a complete FluorineFx-enabled solution, and creating a new project using the options given on this page is what we recommend, this way the WebSite project automatically adds a reference to the service library project.
The FluorineFx Visual Studio Wizard in Visual Studio 2005
In VS, choose File\New\Project… to create an empty project.
In VS2005, choose File\Add\New Project…
In the Installed Templates panel, select the FluorineFx ServiceLibrary project template
The wizard creates the ServiceLibrary (which is just a class library with a reference to the fluorineFx assembly). ServiceLibrary is used for two reasons: your application can run under medium trust (mousebomb: not really sure what exactly this refers to), and it makes architectural separation easier.
The workspace should now look like this:
Choose File\Add\New Web Site…
In the “Installed Templates” selection panel, select the FluorineFx ASP.NET WebSite template
At this point, you should see a structure like this in Solution Explorer:
On the WebSite property panel page you can manage assembly references (if needed).
With that, the solution is created; next comes running and debugging the application.
Debugging with VS2005
Use the Visual Studio .NET debugger to observe your program and service classes’ behavior at runtime.
If this is your first time running the program, set the startup project and start page.
Set the startup project
Set the start page (this tutorial uses the Console.aspx page generated by the wizard, which redirects to the Service browser page). Later you can change the start page to load your client program.
Set breakpoints, start debugging
VS launches the default browser and starts your application, loading the start page. Set the parameter values and click the “Call” button.
You can open as many browsers as you want; any client call will trigger the breakpoint.
VS breakpoint triggered
(Mousebomb: this part of the debugging is illustrated using remoting as an example; we’re just using it as a reference, the debugging method is known to everyone on Earth, so I won’t translate the images and text below.)
Real-time Messaging Applications
Every Real-time Messaging (RTMP (Real-time Messaging Protocol) is the online streaming communication protocol used by Adobe’s FMS product; a literal translation would be “real-time messaging protocol”. RTM (Real-time Messaging) literally means “real-time messaging”.) application has an Application (Application Adapter) object. The Application object can be used to manage the application’s lifecycle, and to accept or reject client connection attempts.
The Application Adapter object is similar to the FCS/FMS Application object.
Application Structure
An ASP.NET web site can support multiple RTM applications. These applications all live in the “apps” directory under the ASP.NET web site root, and are identified by their directory names.
(mousebomb: for example, HelloWorld in the sample is an RTM application
)
An ASP.NET web site directory structure:
WebSite
–apps
–SharedBall
–VideoChat
–VideoRecording
An ASP.NET web site directory structure hosted in IIS:
Inetpub
–wwwroot
–WebSite
–apps
–SharedBall
-persistence
–VideoChat
–VideoRecording
-streams
In this example there are 3 RTM applications: SharedBall, VideoChat, VideoRecording. To connect to the SharedBall application from the client, you need to use an application name like this:
nc = new NetConnection();
nc.connect(“rtmp://localhost:1935/SharedBall”)
Scope Model
In an RTM application, resources are all managed in a tree. Each node in the tree is called a scope. A scope is a stateful object, shared among the group of clients already connected to the same context path. If the scope is a leaf node, it’s called a BasicScope; if the scope has sub-scopes, it’s called a Scope. There are two predefined BasicScopes: SharedObject Scope and BroadcastStream Scope.
Each application has its own scope hierarchy, and the root scope is the WebScope. There’s also a global scope, which is the parent of the WebScope. Each scope has a name. The GlobalScope is named “default”. WebScopes are named after the root level of each application context. Other scopes are named after their respective path names. SharedObject Scopes are named after each SharedObject’s name. BroadcastStream Scopes are named after each stream’s name.
The GlobalScope provides cross-application resource and service sharing.
Except for GlobalScope and BasicScopes, all scopes can be connected to by clients. A scope object can be created as a result of a client connection request. For example, a client might send a request trying to connect to application/room0, when application/room0 doesn’t exist yet. After the connection is established, room0 is created. If the url contains many intermediate-level scopes, all of these scopes will be created. For example, if application/lobby0/room0 is requested and neither lobby0 nor room0 exists, then both lobby0 and room0 will be created.
A typical scope hierarchy would look like this:
GlobalScope(default) –> WebScope(application) –> Scope(room0) –> BroadcastStream(live0), SharedObject(so1)
–> Scope(room1) –> SharedObject(so0)
In the previous example, the code nc.connect(“rtmp://localhost:1935/application”) will connect the client to the WebScope.
Service Hierarchy
The IServiceProvider interface defines a mechanism for retrieving service objects. Every scope object is a service provider.
Services are managed in a tree (the service hierarchy). A service hierarchy consists of several ServiceContainers. A ServiceContainer is used to store instances of the corresponding class, which provides services for its own type. You can get a service instance by passing a type.
A service container is usually bound to a parent. This means that when a service is requested and not found in its container, the container asks its parent, and so on. (Service containers have no concept of children, only parents.) Each scope holds a service container, and this container’s parent is the parent scope’s service container.
At the GlobalScope level, you have services like IstreamableFileFactory and IBWControlService.
At the WebScope level, you have services like IStreamFilenameGenerator, IsharedObjectSecurityService, and so on.
Application Adapter
To write your own application code that works with client connections, handles server-side events, calls client methods, and enforces security, you must implement a custom Application Adapter.
The FluorineFx.Messaging.Adapter.ApplicationAdapter class is used as the base class for new Applications. This class provides methods, shared objects and streams for working with client connections.
In addition, the Application object has callback functions that can be triggered when the application starts and ends, and also when clients connect and disconnect.
An Application Adapter is an application-level scope handler.
Application Configuration
Each RTM application can (optionally) contain a configuration file placed in the application’s root directory. The configuration file is named app.config.
A custom Application Adapter class must be registered in the configuration file.

Connecting to an RTM Application
Flash’s NetConnection class connects the client to the server.
var nc:NetConnection = new NetConnection();
var uri:String = “rtmp://localhost:1935/SharedBall”;
nc.connect( uri );
The name SharedBall is the sample application’s relative application name under the apps directory.
When the application accepts the connection request, the connection becomes available on both the client side (flash.net.NetConnection) and the server side (FluorineFx.Messaging.Api.IConnection).
Application Events
Application events
A custom Application Adapter can override the following methods to provide access at each step in the RTM application’s lifecycle.
Event
Description
public virtual bool AppStart(IScope application)
Called when the application scope starts
public virtual bool RoomStart(IScope room)
Called when the room scope starts
public virtual bool AppConnect(IConnection connection, object[] parameters)
Called each time a new client connects.
The contents of the parameters parameter are the list of parameters passed after the uri in the NetConnection.connect method.
public virtual bool RoomConnect(IConnection connection, object[] parameters)
Called each time a new client connects to the application (room).
The contents of the parameters parameter are the list of parameters passed after the uri in the NetConnection.connect method.
public virtual bool AppJoin(IClient client, IScope application)
Called each time a client joins the application scope. This event is called after the connection is established.
public virtual bool RoomJoin(IClient client, IScope room)
Called each time a client joins the room scope. This event is called after the connection is established.
public virtual bool RoomLeave(IClient client, IScope room)
Called each time a client leaves the room scope. This event is called before the connection disconnects from the scope.
public virtual bool AppLeave(IClient client, IScope application)
Called each time a client leaves the application scope. This event is called before the connection disconnects from the scope.
public virtual bool RoomDisconnect(IConnection connection)
Called each time a client disconnects.
public virtual bool AppDisconnect(IConnection connection)
Called each time a client disconnects.
public virtual bool RoomStop(IScope room)
Called when the room scope stops.
public virtual bool AppStop(IScope application)
Called when the application scope stops.
Order of Execution for Connection Events
Suppose a client is connecting to rtmp://server/app/room1/room2
First, the connection is established, so the user connects to all the scopes that room2 passes through:
app(-> AppConnect)
room1(-> RoomConnect)
room2 (-> RoomConnect)
After the connection is established, the client object is retrieved, and if this is the client’s first connection to this scope, it joins the scope:
app(-> AppJoin)
room1(-> RoomJoin)
room2(-> RoomJoin)
If the same client establishes a second connection to the same scope, only the connect methods are called. If it connects to partially the same scopes, only some of the join methods are called; for example, rtmp://server/app/room1/room3 will trigger:
app(-> AppConnect)
room1(-> RoomConnect)
room3(-> RoomConnect)
room3(-> RoomJoin)
Client RPC Calls
Handling RPC Calls in the Application Adapter
All methods added to an Application Adapter subclass can be called from the client via the NetConnection.call method.
For example, the following server-side code:
public class Application : ApplicationAdapter
{
public string Echo(string msg)
{
return “Echo: “ + msg;
}
}
can be triggered by the following as code snippet on the client:
nc = new NetConnection();
nc.connect(“rtmp://localhost/application”);
nc.onResult = function(obj) {
trace(“The result is “ + obj);
}
nc.call(“Echo”, nc, “Hello”);
If a method has defined a parameter of type Iconnection as its first implicit parameter, then when the client calls that method, the current connection will be filled in automatically.
Calling Client Methods
If a connection implements the IserviceCapableConnection interface, then it supports calling client methods.
To call methods on the client from your application, you’ll first need a reference to the current connection object. To get the active connection, use the FluorineContext.Current.Connection property.
Example:
IServiceCapableConnection connection = FluorineContext.Current.Connection as IServiceCapableConnection;
if (connection != null)
{
object[] args = new object[] { connection.Client.Id };
connection.invoke(“setClientId”, args);
}
Client code snippet:
nc = new NetConnection();
nc.client = this;
nc.connect(“rtmp://localhost/application”);
…
function setClientId( id:String ):void
{
trace(id);
}
(mousebomb: you don’t need to worry about how exactly the client code is implemented; I guarantee it’s compatible in a way that matches this sample code)
If you need to get the result returned by the method, you must provide a class that implements the IPendingServiceCallback interface. In the example below, the Application Adapter implements this interface, and the method call is updated and then passed to the IPendingServiceCallback interface.
public class Application : ApplicationAdapter, IPendingServiceCallback
{
public void ResultReceived(IPendingServiceCall call)
{
…
}
private void CallClient()
{
IServiceCapableConnection connection = FluorineContext.Current.Connection as IServiceCapableConnection;
if (connection != null)
{
object[] args = new object[] { connection.Client.Id };
connection.invoke(“setClientId”, args, this);
}
}
}
In addition, the following ApplicationAdapter helper methods can be used to call client methods:
void InvokeClients(string method, object[] arguments, IPendingServiceCallback callback)
void InvokeClients(string method, object[] arguments, IPendingServiceCallback callback, bool ignoreSelf)
void InvokeClients(string method, object[] arguments, IPendingServiceCallback callback, bool ignoreSelf, IScope targetScope)
The targetScope parameter sets the scope that the client is connected to, on which the call will be made.
(mousebomb: we don’t need sections like Shared Objects, ignore them)
Examples
For RTMP examples see: X:\Program Files\FluorineFx\Samples\Flash\Rtm
