Accessing MSD-based map services with server object extensions


Summary
When using MSD-based map services with server object extensions (SOEs), you can do quite a bit if you stick to the MapServer-related classes. Also, you can use IMapServerDataAccess to access the source data for the layers in your map. From there you can do many things to work with the data directly.

In this topic


About accessing MSD-based map services

This topic explains how to work with MSD-based map services when writing an SOE. This is the type of service that you get when you work with the Map Service Publishing toolbar in ArcMap, which publishes the map to the server using a map service definition (.msd file). MSD-based map services use a faster drawing engine than the traditional, MXD-based map services, so there are benefits to writing your SOE to support them. Also, ArcGIS Server 10.1 will only support map services that use this drawing engine.
Because MSD-based map services use a completely different drawing engine and source file than MXD-based services, they draw very quickly. However, this also means that they do not support full ArcObjects access from the Carto library. When working with optimized map services, you cannot use any ArcObjects directly related to the map document, such as IMapServerObjects, IMap, ILayer, and IFeatureLayer.
It turns out you can still do quite a few things when you use an MSD-based map service with your SOE. The following information summarizes what is available.

What you can do

The Carto library contains a MapServer class that represents the map service. There are a number of supporting classes and interfaces surrounding MapServer that give you information such as the layer names, whether the service has a cache or not, and how queries should be performed with the service.
On the MapServer page of the .NET Carto object model diagram (OMD), you can see these classes and interfaces. You can use them with any type of map service, whether the source map is an MSD or an MXD. Avoid using other classes in the Carto library with MSD-based map services.

Getting to the source data

The MapServer class implements the interface IMapServerDataAccess, which allows you to access the data sources of the layers in your map. Using the GetDataSource method on this interface, you can access the IFeatureClass, IRaster, or ITable interface of the underlying data.
The typical pattern is to use the MapServer-related classes and interfaces to discover the layer names and indices in your map service, then use IMapServerDataAccess to get to the data beneath. Once you obtain the source data, you can do many things with it using ArcObjects, such as opening feature cursors or topological operators. You are safe as long as you avoid the previously mentioned MXD-specific classes from the Carto library. The following code example shows getting the source feature class for a map layer named "States".
[C#]
string mapLayerToFind = "States";
//Access the map service and its layer infos.
ESRI.ArcGIS.Carto.IMapServer3 mapServer = (ESRI.ArcGIS.Carto.IMapServer3)
    serverObjectHelper.ServerObject;
string mapName = mapServer.DefaultMapName;
IMapLayerInfos layerInfos = mapServer.GetServerInfo(mapName).MapLayerInfos;
IMapLayerInfo layerInfo;

// Find the index of the layer of interest.
int c = layerInfos.Count;
int layerIndex = 0;
for (int i = 0; i < c; i++)
{
    layerInfo = layerInfos.get_Element(i);
    if (layerInfo.Name == mapLayerToFind)
    {
        layerIndex = i;
        break;
    }
}

// Access the source feature class.
IMapServerDataAccess dataAccess = (IMapServerDataAccess)mapServer;
IFeatureClass fc = (IFeatureClass)dataAccess.GetDataSource(mapName, layerIndex);
[VB.NET]
Dim mapLayerToFind As String = "States"
'Access the map service and its layer infos.
Dim mapServer As ESRI.ArcGIS.Carto.IMapServer3 = DirectCast(serverObjectHelper.ServerObject, ESRI.ArcGIS.Carto.IMapServer3)
Dim mapName As String = mapServer.DefaultMapName
Dim layerInfos As IMapLayerInfos = mapServer.GetServerInfo(mapName).MapLayerInfos
Dim layerInfo As IMapLayerInfo
' Find the index of the layer of interest.
Dim c As Integer = layerInfos.Count
Dim layerIndex As Integer = 0
For i As Integer = 0 To c - 1
    layerInfo = layerInfos.get_Element(i)
    If layerInfo.Name = mapLayerToFind Then
        layerIndex = i
        Exit For
    End If
Next

' Access the source feature class.
Dim dataAccess As IMapServerDataAccess = DirectCast(mapServer, IMapServerDataAccess)
Dim fc As IFeatureClass = DirectCast(dataAccess.GetDataSource(mapName, layerIndex), IFeatureClass)
The previous code example gets all the layer information for the map service. IMapLayerInfos and IMapLayerInfo are legal to use because they do not require access to a map document (they just help you get information that the service exposes).
The code example then iterates through the layer infos until it finds the index of the layer named “States”. That index is then passed into IMapServerDataAccess.GetDataSource(). At this point you’ve reached your goal of accessing the source data interface IFeatureClass.
For brevity, the previous code example contains no error handling; but you might want to add a check that IMapLayerInfo.Type is equal to “Feature Layer” before you cast the result to IFeatureClass.

Registering SOEs that support MSD-based map services

When you register the SOE, you must also set a property defining that the SOE supports MSD-based map services. This property is called SupportsMSD and it is a Boolean. You have to set it to True for your SOE to appear in the list when you publish an MSD-based map service.
If you’re following the .NET SOE samples out of the software development kit (SDK), you’re probably registering your SOE using a console application that calls IServerObjectAdmin2.AddExtensionType(). In this application, you set the properties of your SOE.
The following code example shows how to set up the properties to support MSD-based map services (notice the call to IServerObjectExtensionType3.Info.SetProperty() that sets the SupportsMSD property):
[C#]

IServerObjectExtensionType3 serverObjectExtensionType = 
    (IServerObjectExtensionType3)serverObjectAdmin.CreateExtensionType();
// Set properties for the SOE.
serverObjectExtensionType.CLSID = "MySOE.MySOE";
. . . serverObjectExtensionType.Info.SetProperty("SupportsMSD", "true");
// Register the SOE with the server.
serverObjectAdmin.AddExtensionType("MapServer", serverObjectExtensionType);
[VB.NET]
Dim serverObjectExtensionType As IServerObjectExtensionType3 = DirectCast(serverObjectAdmin.CreateExtensionType(), IServerObjectExtensionType3)

' Set properties for the SOE.
serverObjectExtensionType.CLSID = "MySOE.MySOE"

. . .

serverObjectExtensionType.Info.SetProperty("SupportsMSD", "true")
' Register the SOE with the server.
serverObjectAdmin.AddExtensionType("MapServer", serverObjectExtensionType)