Monday, September 9, 2013

Using System.AppDomain to share data between Automation Objects - Part 1

This one is for advance Application Server users.

When writing complex .NET scripts within automation objects, you might find the need to share information between objects that is not of a standard ArchestrA data type. In other words: if your script is using a .NET type that is not compatible with the data types available for a UDA, how do you share that data between two or more objects in your Galaxy? If you read the title of this post you guessed right: using the .NET System.AppDomain class.

There is one caveat, though. You can only share the data between objects in the same AppEngine.

Note: The AppDomain class provides an isolated environment to execute applications. We are using it as a "trick" to share data within your application, but it's not its real purpose.

In this 2-part article, I will walk you through an example sharing a connection to a SQL Server database. In Part 1 I will show you how to create and make the connection available to the rest of the application. In Part 2 I will show you how to access the connection from a different object.

Since the AppDomain works within the confines of a single AppEngine, I find it better to script the AppEngine to handle the connection itself, that is, opening and closing the connection to the SQL Server database. The database connection should be open while the AppEngine is running, so a Startup and a Shutdown script should do the trick.

Declarations section:

dim conn as System.Data.SqlClient.SqlConnection;
Startup script:

'Create and open connection to database.
conn = new System.Data.SqlClient.SqlConnection();
conn.ConnectionString = "Server=(local);Database=Runtime;Trusted_Connection=True";
conn.Open();

'Place database connection in AppDomain.
System.AppDomain.CurrentDomain.SetData("RuntimeDbConnection", conn);
Shutdown script:

'Remove database connection from AppDomain.
System.AppDomain.CurrentDomain.SetData("RuntimeDbConnection", null);

'Close database connection.
conn.Close();
So what is going on here? This is the main workflow for this script:
  1. On startup, create the connection to the database.
  2. Place the connection in the current domain (you could create a new domain, but it's not necessary for this purpose)
  3. On shutdown, remove the connection from the current domain.
  4. Close the connection to the database.
Let's take a closer look at this script.

dim conn as System.Data.SqlClient.SqlConnection;
The connection itself resides in the AppEngine. It needs to exist throughout the execution of the AppEngine so it must be declared in the Declarations section of the script.

conn = new System.Data.SqlClient.SqlConnection();
conn.ConnectionString = "Server=(local);Database=Runtime;Trusted_Connection=True";
conn.Open();
When the AppEngine starts, simply open the connection to the database. For this example, we're creating a connection to the Historian database (Runtime) in the local computer… local to the where the AppEngine is deployed.

System.AppDomain.CurrentDomain.SetData("RuntimeDbConnection", conn);
Yes, is this simple. Place the data you want to share in the current domain and give it a name. In this example the data to share is conn and the name is RuntimeDbConnection. You will use this name to retrieve the data from a different object.

System.AppDomain.CurrentDomain.SetData("RuntimeDbConnection", null);
When the AppEngine shuts down, "remove" the data in the current domain by assigning null to the data name used before.

conn.Close();
Finally, close the database connection. Some people don't bother to close the connection and let the session time out; this is not good practice. You should always close your database connections when you're done using them.

On Part 2 I will show you how to access the database connection from a different object.

3 comments:

  1. dead site and no Part 2

    ReplyDelete
  2. Interesting post, thank you
    I have a question about redundant appEngine. Can I have the same script running on 2 engines (One and its redundant) and consequently, 2 AppDomain with the same "Name" ?
    Eliceo

    ReplyDelete