Last month I got a new assignment to develop a tool that changes the layers’ connection in a MXD file and publish it in ArcGis Server. It is fairly easy to do it using ArcMap but we have too many environments/servers and whatever we can automate should be automated.
Since then the team went to a Systematics Event (ESRI local provider) where they talked about the new stuff in version 10.1, namely that publishing will only support MSD files (not MXD files) – so the task got changed a bit. For more information on MSD functionality and Performance considerations.
Finding how to change the connection of the layers was easy enough with the IMSDHelper interface:
- private const bool UseRelativePath = true;
- private const bool ValidateLayerConnection = false;
- /// <summary>
- /// Changes the SDE connection string for all the layers in the MSD file
- /// </summary>
- /// <param name="msdFilePath"></param>
- /// <param name="connectionString"></param>
- /// <param name="resultMsdFile">result file is relative path</param>
- public static void ChangeConnection(string msdFilePath, string connectionString, string resultMsdFile)
- {
- IMSDHelper helper = new MSDHelper();
- helper.Open(msdFilePath);
- var maps = helper.GetMaps();
- for (var i = 0; i < maps.Count; i++)
- {
- var layers = helper.GetLayers(maps.Element[i]);
- for (var j = 0; j < layers.Count; j++)
- {
- helper.PutWorkspaceConnectionStringInLayer(layers.Element[j], connectionString, ValidateLayerConnection);
- }
- }
- helper.SaveAs(resultMsdFile, UseRelativePath);
- }
We simply iterate through all the maps and all the inner layers and change the connection to the given one.
But what about Publishing the MSD automatically? This proved to be a bit more problematic. It was fairly easy to find a Python script using arcPy that publishes MSD files. But less so on ArcObjects code, in the end I found this forum post which led me to this code (just run it through Google Translate since it’s in Chinese). The code looks like this:
- public static void PublishToServer(string mapFilePath, string serverName, string serviceName)
- {
- IGISServerConnection gisServerConnection = new GISServerConnectionClass();
- gisServerConnection.Connect(serverName);
- var serverObjectAdmin = gisServerConnection.ServerObjectAdmin;
- var configuration = (IServerObjectConfiguration2)serverObjectAdmin.CreateConfiguration();
- // release the name of the Service, required
- configuration.Name = serviceName;
- // release the type of service, such as: MapServer, GeocodeServer
- configuration.TypeName = ServiceConfigurationTypeName;
- configuration.Description = serviceName;
- // Service Description
- SetDefaultServerConfigurations(configuration, mapFilePath, serverName);
- // add service to the Server
- serverObjectAdmin.AddConfiguration(configuration);
- // start the service
- serverObjectAdmin.StartConfiguration(configuration.Name, configuration.TypeName);
- }
This is to set the default values of my organization:
{
var properties = configuration.Properties;
// Set the path of the file
properties.SetProperty("FilePath", mapFilePath);
// image output directory
properties.SetProperty("outputdir", "c:\\arcgisserver\\arcgisoutput");
// image output virtual path
properties.SetProperty("VirtualOutPutDir", "http://" + serverName + "/arcgisoutput");
// image type supported by
properties.SetProperty("SupportedImageReturnTypes", "URL");
(there are more settings that can be found here)
I found that it is best to look at existing services, for that I added the capability of getting your service settings in XML format:
- public static string GetServiceConfiguration(string serverName, string serviceName)
- {
- IGISServerConnection gisServerConnection = new GISServerConnectionClass();
- gisServerConnection.Connect(serverName);
- var serverObjectAdmin = gisServerConnection.ServerObjectAdmin;
- var configuration = (IServerObjectConfiguration4)serverObjectAdmin.GetConfiguration(serviceName, ServiceConfigurationTypeName);
- return configuration.Serialize();
- }
The output of this method looks like this:
- <ServerObjectConfiguration>
- <Description>PublishDemoIi</Description>
- <Properties>
- <FilePath>C:\Install\MsdUtils\Demo.msd</FilePath>
- <outputdir>c:\arcgisserver\arcgisoutput</outputdir>
- <VirtualOutPutDir>http://server/arcgisoutput</VirtualOutPutDir>
- <SupportedImageReturnTypes>URL</SupportedImageReturnTypes>
- <MaxImageHeight>2048</MaxImageHeight>
- <MaxRecordCount>50000</MaxRecordCount>
- <MaxBufferCount>100</MaxBufferCount>
- <MaxImageWidth>2048</MaxImageWidth>
- <IsCached>false</IsCached>
- <CacheOnDemand>false</CacheOnDemand>
- <IgnoreCache>false</IgnoreCache>
- <ClientCachingAllowed>true</ClientCachingAllowed>
- <CacheDir>c:\arcgisserver\arcgiscache\GtmPublishDemoIi</CacheDir>
- <SOMCacheDir>c:\arcgisserver\arcgiscache</SOMCacheDir>
- <UseLocalCacheDir>true</UseLocalCacheDir>
- </Properties>
- <Extension>
- <TypeName>FeatureServer</TypeName>
- <Enabled>true</Enabled>
- <Properties>
- <EnableZDefaults>false</EnableZDefaults>
- <ZDefaultValue>0</ZDefaultValue>
- </Properties>
- <Info>
- <WebEnabled>true</WebEnabled>
- <SupportsMSD>true</SupportsMSD>
- <WebCapabilities>Query</WebCapabilities>
- </Info>
- </Extension>
- <Extension>
- <TypeName>...</TypeName>
- <Enabled>false</Enabled>
- <Properties>
- </Properties>
- <Info>
- </Info>
- </Extension>
- <Info>
- <WebEnabled>true</WebEnabled>
- <WebCapabilities>Map,Query,Data</WebCapabilities>
- </Info>
- <IsPooled>true</IsPooled>
- <MinInstances>1</MinInstances>
- <MaxInstances>2</MaxInstances>
- <InstancesPerContainer>1</InstancesPerContainer>
- <WaitTimeout>60</WaitTimeout>
- <IdleTimeout>-1</IdleTimeout>
- <UsageTimeout>600</UsageTimeout>
- <CleanupTimeout>30</CleanupTimeout>
- <ServiceKeepAliveInterval>-1</ServiceKeepAliveInterval>
- <StartupTimeout>300</StartupTimeout>
- <Isolation>high</Isolation>
- <StartupType>automatic</StartupType>
- </ServerObjectConfiguration>
As you can see the properties in the XML correspond perfectly with the properties settings.
To test the creation of the service you can look at ArcGis Server Manager:
http://ServerName/ArcGIS/manager/default.aspx
Where you can tweak the settings (as you can see I had 5 tries till I got it right…).
Also you can test the service using the REST API :
http://ServerName/ArcGIS/rest/services
Looking into the FeatureServer link you will find in the bottom “Supported Operations: Query” where you can test the Feature service queries:
Some points:
- Using PublishToServer needs MSD file located on the server.
- In order to use PublishToServer user must be an admin on the server (otherwise the call gisServerConnection.ServerObjectAdmin would fail)
- You must clear ArcGis rest API cache before using the service (or you won’t see it in the rest/services url) – for doing that automatically see my previous post: Clearing ArcGIS Server REST API Cache
I have posted the complete tool in my Codeplex project: ArcGisServerTools, MsdUtils, ArcGisServerUtils.
Resources:
ArcGis Server Forum: Promote map service from one server stage to another in automated fashion?
ArcObjects Forum: Publish MXD to server in ArcObjects C#
Keywords: MSD, ArcObjects, ArcGis Server, ESRI