Working with the ArcGIS Server ArcObjects API  

Working with server contexts


 


To this point, this chapter has focused on the use of server objects to perform the functionality that they expose through their coarse-grained interfaces. The Web controls' functionality is based on the functionality exposed by these server objects. If you want your application to go beyond simple mapping and geocoding using server objects and Web controls, you must become familiar with working with server contexts as well as the ArcObjects programming model.



The ServerContext object provides access to a context in the GIS server and methods for creating and managing objects within that context.



The ServerObjectManager object provides methods for getting information about the GIS server and for creating server contexts for use by an application.

Getting and Releasing Server Contexts

You get a server context using the CreateServerContext method on IServerObjectManager, which hands back an IServerContext interface on the server context. The IServerContext interface has a number of methods for helping you manage the objects you create within server contexts. So far in the code examples in this chapter the use of three of these methods, specifically CreateObject, SaveObject, and LoadObject , have been shown. The use of these and other methods will be described in more detail in this section.

When developing applications with ArcGIS Server, all ArcObjects that your application creates and uses live within a server context. A server context is a reserved space within the server dedicated to a set of running objects. Server objects also reside in a server context. To get a server object, you actually get a reference to its context, then get the server object from the context:

[Visual Basic .NET]
Dim pServerContext as IServerContext = pServerObjectManager.CreateServerContext("RedlandsMap","MapServer")
Dim pMapServer as IMapServer = pServerContext.ServerObject

You can also create empty server contexts. You can use an empty context to create ArcObjects on the fly within the server to do ad hoc GIS processing:

[Visual Basic .NET]
Dim IServerContext as IServerContext = pServerObjectManager.CreateServerContext("","")
Dim pWorkspaceFactory as IWorkspaceFactory = pServerContext.CreateObject("esriDataSourcesGDB.SdeWorkspaceFactory")

An empty server context is useful when you want to create objects for your application's use in the server but do not require the use of a preconfigured server object. Empty contexts can be used to create any type of object, such as a connection to a workspace as shown above. Since server objects are ArcObjects, you can also use empty contexts to create server objects (MapServer, GeocodeServer, GeodataServer, GlobeServer ) on-the-fly. Empty server contexts are non-pooled and have high isolation.

When your application is finished working with a server context, it must release it back to the server by calling the ReleaseContext method. If you allow the context to go out of scope without explicitly releasing it, it will remain in use and be unavailable to other applications until it is garbage collected. Once a context is released, the application can no longer make use of any objects in that context. This includes both objects that you may have obtained from or created in the context.

[Visual Basic .NET]
Dim pServerContext as IServerContext = pServerObjectManager.CreateServerContext("RedlandsMap","MapServer")
Dim pMapServer as IMapServer = pServerContext.ServerObject
' Do something with the object
pServerContext.ReleaseContext()

Creating Objects in the Server

Client machines (for example, the Web server machine) require only the Web ADF runtime be installed to run ArcGIS Server applications. The Web ADF runtime does not install ArcObjects, so these applications do not have the ability to create local ArcObjects. All ArcObjects that your application uses should be created within a server context using the CreateObject method on IServerContext. In previous examples, you have seen CreateObject used to create an ImageDescription object for use in ExportMapImage .

ArcGIS Server applications written in .NET should not use New to create local ArcObjects but should always create objects within the server by calling CreateObject on IServerContext :

[Visual Basic .NET]

Incorrect:

Dim pPoint as IPoint = New Point

Correct:

Dim pPoint as IPoint = pServerContext.CreateObject("esriGeometry.Point")

Use CreateObject when you need to create an object for use in your application.

[Visual Basic .NET]
Dim pPointCollection as IPointCollection = pServerContext.CreateObject("esriGeometry.Polygon")

CreateObject will return a proxy to the object that is in the server context. Your application can make use of the proxy as if the object was created locally within its process. If you call a method on the proxy that hands back another object, that object will actually be in the server context, and your application will be handed back a proxy to that object. In the above example, if you get a point from the point collection using IPointCollection::Point , the point returned will be in the same context as the point collection.

A proxy object is a local representation of a remote object. The proxy object controls access to the remote object by forcing all interaction with the remote object to be via the proxy object. The supported interfaces and methods on a proxy object are the same as those supported by the remote object. You can make method calls on, and get and set properties of, a proxy object as if you were working directly with the remote object.

If you add a point to the point collection using IPointCollection::AddPoint, you should create that point in the same context as the point collection.

[Visual Basic .NET]
Dim pPointCollection as IPointCollection = pServerContext.CreateObject("esriGeometry.Polygon")

Dim pPoint as IPoint = pServerContext.CreateObject("esriGeometry.Point")
pPoint.X = 1
pPoint.Y = 1

pPointCollection.AddPoint (pPoint)

It's important to understand how your application is making use of server contexts as it does its work because objects that are used together should be in the same context. For example, if you create a point object to use in a spatial selection to query features in a feature class, the point should be in the same context as the feature class. This becomes important if your application makes use of more than one server context. It may be necessary to copy objects from one context to another.

Also, you should not directly use objects in a server context with local objects in your application and vice versa. You can indirectly use objects or make copies of them. For example, if you have a Point object in a server context, you can get its X, Y properties and use them with local objects or use them to create a new local point. Don't directly use the point in the server context as, for example, the geometry of a local graphic element object.

Consider the following examples. In each example, assume that objects with Remote in their names are objects in a server context as in:

[Visual Basic .NET]
Dim pRemotePoint as IPoint = pServerContext.CreateObject("esriGeometry.Point")

while objects with Local in their name are objects created locally as in:

Dim pLocalPoint as IPoint = New Point

You can't set a local object to a remote object:

' this is incorrect
Set pLocalPoint = pRemotePoint

' this is also incorrect
Set pLocalElement.Geometry = pRemotePoint

Do not set a local object, or a property of a local object, to be an object obtained from a remote object:

' this is incorrect
Set pLocalPoint = pRemotePointCollection.Point(0)

When calling a method on a remote object, don't pass in local objects as parameters:

' this is incorrect
Set pRemoteWorkspace = pRemoteWorkspaceFactory.Open(pLocalPropertySet,0)

You can get simple data types (double, long, string, and so forth) that are passed by value from a remote object and use them as properties of a local object as in:

' this is OK
pLocalPoint.X = pRemotePoint.X
pLocalPoint.Y = pRemotePoint.Y

The SaveObject and LoadObject methods allow you to serialize objects in the server context to a string, then deserialize them back into objects. You have already seen how these methods can be used to manage state in your application while making stateless use of a pooled server object (see previous topic). These methods also allow you to copy objects between contexts. Any object that supports IPersistStream can be saved and loaded using these methods. For example, in an application that makes use of a MapServer object for mapping and a GeocodeServer object for geocoding, the GeocodeServer and MapServer will be running in different contexts. If you use the GeocodeServer object to locate an address and you want to draw the resulting point that GeocodeAddress returns on your map, you need to copy the point into your MapServer's context:

[Visual Basic .NET]
Dim pServerContext as IServerContext = pSOM.CreateServerContext("RedlandsMap", "MapServer")
			Dim pServerContext2 As IServerContext = pSOM.CreateServerContext("RedlandsGeocode", "GeocodeServer")
Dim pGCServer As IGeocodeServer = pServerContext2.ServerObject

Dim pPropertySet As IPropertySet = pServerContext2.CreateObject("esriSystem.PropertySet")
pPropertySet.SetProperty ("Street", "380 New York St")

Dim pResults As IPropertySet = pGCServer.GeocodeAddress(pPropertySet, Nothing)
Dim pPoint As IPoint = pResults.GetProperty("Shape")

' copy the Point to the Map's server context
Dim sPoint As String = pServerContext2.SaveObject(pPoint)
Dim pPointCopy As IPoint = pServerContext.LoadObject(sPoint)

pServerContext2.ReleaseContext()

' add the point as a graphic to the map description and redraw the map

pServerContext.ReleaseContext()



			

This diagram illustrates the use of SaveObject and LoadObject to copy objects between server contexts:
1. The client application gets or creates an object within a server context.
2. The application uses the SaveObject method on the object's context to serialize the object as a string that is held in the application's session state.
3. The client application gets a reference to another server context and calls the LoadObject method, passing in the string created by SaveObject. LoadObject creates a new instance of the object in the new server context.

A PropertySet is a generic class that is used to hold any set of properties. A PropertySet's properties are stored as name/value pairs. Examples for the use of a property set are to hold the properties required for opening a Spatial Database Engine™ (SDE®) workspace or geocoding an address.

Managing Objects in a Server Context

As your application creates and uses various objects within a particular context, you may want a convenient place to store references to commonly used objects within the context. You can do this by using the server context's object dictionary to keep track of these objects during the lifetime of the context. You can use the context's dictionary as a convenient place to store objects that you create within the context. Note that this dictionary is itself valid only as long as you hold on to the server context and it's emptied when you release the context. You can use this dictionary to share objects created within a context between different parts of your application that have access to the context.

For example, your application may make repeated use of a geometry object across requests. Rather than creating the geometry object over and over again, your application can store the geometry object in the context's dictionary so you can use it multiple times without having to re-create it. This is illustrated below.

You add objects to and retrieve objects from the dictionary using the SetObject and GetObject methods, respectively. An object that is set in the context will be available until it is removed (by calling Remove or RemoveAll) or until the context is released.

[Visual Basic .NET]
Dim pPointCollection as IPointCollection = pServerContext.CreateObject("esriGeometry.Polygon")

pServerContext.SetObject ("myPoly", pPointCollection)
Dim pPoly as IPolygon = pServerContext.GetObject("myPoly")

Use the Remove and RemoveAll methods to remove an object from a context that has been set using SetObject . Once an object is removed, a reference to it can no

Use the Remove and RemoveAll methods to remove an object from a context that has been set using SetObject. Once an object is removed, a reference to it can no longer be obtained using GetObject. Note that if you do not explicitly call Remove or RemoveAll, you can still not get references to objects set in the context after the context has been released.

[Visual Basic .NET]
pServerContext.Remove ("myPoly")

A server context contains an object dictionary that serves as a convenient place for you to store references to commonly used objects. Use the SetObject and GetObject methods on IServerContext to work with the object dictionary.

Writing output

When your application performs operations using ArcObjects running in server contexts, those operations may need to write out data to disk. For example, the ExportMapImage method on a map server object writes images to disk and the CheckOut method on a geodata server object writes personal geodatabases to disk. You may have other applications that need to write data; for example, an application that uses geoprocessing objects to create shapefiles needs to write those shapefiles to disk where they can be downloaded from.

Typically, you will want these files to be cleaned up by the server after some period of time. To ensure this happens, your applications should write their output to a server directory.

The set of a GIS server's server directories is available by calling GetServerDirectoryInfos on the IServerObjectManager interface on the server object manager. For your files to be cleaned up when written into that server directory, they must follow a file naming convention. The GIS server will delete all files in a server directory that are prefixed with "_ags_". Any files written to an output directory that are not prefixed with "_ags_" will not be cleaned by the GIS server.

The following code shows how you can use the GetServerDirectoryInfos method on IServerObjectManager to get a server directory and create a new personal geodatabase:

[Visual Basic .NET]
Dim pServerContext As IServerContext = pSOM.CreateServerContext("", "")

Dim pWSF As IWorkspaceFactory = pServerContext.CreateObject("esriDataSourcesGDB.AccessWorkspaceFactory")

Dim pEnumSDI As IEnumServerDirectoryInfo = pSOM.GetServerDirectoryInfos
Dim pSDI As IServerDirectoryInfo = pEnumSDI.Next

Dim pProps As IPropertySet = pServerContext.CreateObject("esriSystem.PropertySet")

' this database will be cleaned by the GIS server
pProps.SetProperty ("DATABASE", pSDI.Path & "\_ags_db1.mdb")
pWSF.Create (pSDI.Path, "_ags_db1", pProps, 0)

' this database will not be cleaned by the GIS server
pProps.SetProperty ("DATABASE", pSDI.Path & "\db2.mdb")
pWSF.Create (pSDI.Path, "db2", pProps, 0)

' this database will not be cleaned by the GIS server
pProps.SetProperty ("DATABASE", pSDI.Path & "\db2.mdb")
pWSF.Create (pSDI.Path, "db2", pProps, 0)

This code creates two geodatabases, one named such that it will be cleaned by the GIS server, one named such that it will not be cleaned by the GIS server.

A PropertySet is a generic class that is used to hold any set of properties. A PropertySet's properties are stored as name/value pairs. Examples for the use of a property set are to hold the properties required for opening an SDE workspace or geocoding an address.

Working with ArcGIS Server extensions

If your server object container machines have licenses for the Spatial, 3D, Network or Data Interoperability extensions for ArcGIS Server, your applications can make use of the functionality that is unlocked by that license.

You do not need to do any explicit calls to get a license when you want to use an object that requires a license. Just create the object on the server and use it. If the server object container machine is not licensed, then any method calls you make on the object will fail.