Publish an image service and set configurations
ISConfig.cs
// Copyright 2010 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

using System;
using System.IO;
using ESRI.ArcGIS;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Server;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.DataSourcesRaster;
namespace ISConfig
{
    /// <summary>
    /// 1. Description:
    /// This sample demonstrate how to create an image service and set configurations based on data source types (raster dataset, mosaic dataset, compiled image service definition, raster layer); it also have additional features to start,stop,delete image service programmatically.
    /// The user running this utility needs to be in the agsadmin group on ArcGIS Server; and needs access to data source.
    /// The application can be run locally on AGSServer machine (localhost), or remotely. If source data is iscdef, image server must be already registered on ArcGIS Server.
    /// 2. Case sensitivity:  
    /// (1) switches are case sensitive. 
    /// (2) when publish a service, the service name is case sensitive
    /// e.g. If it's published to a folder, e.g. Temporary/Test1. "Temporary" must match the case.
    /// 3. Usage:
    /// Run from command line environment. Usage. <>: required parameter; |: pick one.
    /// isconfig -o publish -h <host> -d <datapath> -n <configName>
    /// isconfig -o <delete|start|stop|pause> -h <host> -n <configName>
    /// isconfig -o <list> -h <host>
    /// Example 1: isconfig -o publish -h localhost -d \\myserver\data\test.gdb\mdtest -n mdtest
    /// Example 2: isconfig -o stop -h myservername -n mdtest
    /// Example 3: isconfig -o list -h myservername
    /// </summary>
    class ISConfig
    {
        #region static variables
        private static string sourcePath = ""; //data source path: a raster dataset, an iscdef, a mosaic dataset
        private static string host = ""; //host machine; use "localhost" for local ags server
        private static string configName = ""; //image service configuration name
        private static IGISServerConnection2 gisServerConnection = null;
        private static IRasterDataset rasterDataset = null;

        #endregion

        [STAThread]
        public static void Main(string[] args)
        {
            try
            {
                //validation
                if (!ValidateParams(args))
                    return;
                //license           
                if (!InitLicense())
                    return;
                //retrieve parameters
                Retrieve_Params(args);
                string operation = args[1];
                switch (operation.ToLower())
                {
                    case "publish":
                        CreateISConfig();
                        break;
                    case "delete":
                        DeleteService();
                        break;
                    case "start":
                        StartService();
                        break;
                    case "stop":
                        StopService();
                        break;
                    case "pause":
                        PauseService();
                        break;
                    case "list":
                        ListServices();
                        break;
                }
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
            }
        }


        #region management operations
        /// <summary>
        /// create image service configuration
        /// </summary>
        private static void CreateISConfig()
        {
            try
            {
                if (!ConnectAGS(host)) return;
                esriImageServiceSourceType sourceType = GetSourceType(sourcePath);
                //connect to ArcGIS Server and create configuration
                IGISServerConnection gisServerConnection = new GISServerConnectionClass();
                gisServerConnection.Connect(host);
                IServerObjectAdmin soAdmin = gisServerConnection.ServerObjectAdmin;
                IServerObjectConfiguration soConfig = (IServerObjectConfiguration)soAdmin.CreateConfiguration();

                //set general service parameters
                soConfig.Name = configName;
                soConfig.TypeName = "ImageServer";
                soConfig.StartupType = esriStartupType.esriSTAutomatic;
                soConfig.IsPooled = true;
                soConfig.IsolationLevel = esriServerIsolationLevel.esriServerIsolationHigh;
                soConfig.MinInstances = 1;
                soConfig.MaxInstances = 2;
                IPropertySet propertySet_Recycle = soConfig.RecycleProperties;
                propertySet_Recycle.SetProperty("Start", "00:00");
                propertySet_Recycle.SetProperty("Interval", "86400");
                IPropertySet propertySet = soConfig.Properties;
                if (sourceType == esriImageServiceSourceType.esriImageServiceSourceTypeCatalog)//(sourceDataPath.ToLower().EndsWith(".iscdef"))
                    propertySet.SetProperty("ServiceDefinition", sourcePath);
                else
                    propertySet.SetProperty("Path", sourcePath);
                propertySet.SetProperty("SupportedImageReturnTypes", "URL");

                //virtual directory
                IEnumServerDirectory dirs = soAdmin.GetServerDirectories();
                dirs.Reset();
                IServerDirectory serverDir = dirs.Next();
                while (serverDir != null)
                {
                    if (((IServerDirectory2)serverDir).Type == esriServerDirectoryType.esriSDTypeOutput)
                    {
                        propertySet.SetProperty("OutputDir", serverDir.Path);
                        propertySet.SetProperty("VirtualOutputDir", serverDir.URL);
                        break;
                    }
                    serverDir = dirs.Next();
                }


                //properties for a mosaic dataset;
                if (sourceType == esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset)
                {
                    IFunctionRasterDataset functionRasterDataset = (IFunctionRasterDataset)rasterDataset;
                    IPropertySet propDefaults = functionRasterDataset.Properties;
                    propertySet.SetProperty("MaxImageHeight", propDefaults.GetProperty("MaxImageHeight"));//4100
                    propertySet.SetProperty("MaxImageWidth", propDefaults.GetProperty("MaxImageWidth"));//15000
                    propertySet.SetProperty("AllowedCompressions", propDefaults.GetProperty("AllowedCompressions"));//"None,JPEG,LZ77"
                    propertySet.SetProperty("DefaultResamplingMethod", propDefaults.GetProperty("DefaultResamplingMethod"));//0
                    propertySet.SetProperty("DefaultCompressionQuality", propDefaults.GetProperty("DefaultCompressionQuality"));//75
                    propertySet.SetProperty("MaxRecordCount", propDefaults.GetProperty("MaxRecordCount"));//500
                    propertySet.SetProperty("MaxMosaicImageCount", propDefaults.GetProperty("MaxMosaicImageCount"));//20
                    propertySet.SetProperty("MaxDownloadImageCount", propDefaults.GetProperty("MaxDownloadImageCount"));//20
                    propertySet.SetProperty("AllowedFields", propDefaults.GetProperty("AllowedFields"));//"Name,MinPS,MaxPS,LowPS,HighPS,CenterX,CenterY"
                    propertySet.SetProperty("AllowedMosaicMethods", propDefaults.GetProperty("AllowedMosaicMethods"));//"Center,NorthWest,LockRaster,ByAttribute,Nadir,Viewpoint,Seamline"
                    propertySet.SetProperty("AllowedItemMetadata", propDefaults.GetProperty("AllowedItemMetadata"));//"Full"
                    //propertySet.SetProperty("DownloadDir", ""); //put the download dir here
                    //propertySet.SetProperty("VirutalDownloadDir", ""); //put the virtual download dir here
                }
                else if (sourceType != esriImageServiceSourceType.esriImageServiceSourceTypeCatalog) //not iscdef
                {
                    propertySet.SetProperty("MaxImageHeight", 4100);
                    propertySet.SetProperty("MaxImageWidth", 15000);
                    propertySet.SetProperty("AllowedCompressions", "None,JPEG,LZ77");
                    propertySet.SetProperty("DefaultResamplingMethod", 0);
                    propertySet.SetProperty("DefaultCompressionQuality", 75);
                }

                //enable web capabilities
                IServerObjectConfiguration2 soConfig2 = (IServerObjectConfiguration2)soConfig;
                soConfig2.Info.SetProperty("WebEnabled", "true");
                if (sourceType == esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset)
                    soConfig2.Info.SetProperty("WebCapabilities", "Image,Catalog,Metadata,Download,Pixels");
                else
                    soConfig2.Info.SetProperty("WebCapabilities", "Image,Metadata");

                //enable wcs, assume data has spatial reference
                soConfig2.set_ExtensionEnabled("WCSServer", true);
                IPropertySet propertySetWCS = soConfig2.get_ExtensionInfo("WCSServer");
                propertySetWCS.SetProperty("WebEnabled", "true");


                //enable wms
                soConfig2.set_ExtensionEnabled("WMSServer", true);
                IPropertySet propertySetWMS = soConfig2.get_ExtensionInfo("WMSServer");
                propertySetWMS.SetProperty("WebEnabled", "true");

                //add configuration and start
                soAdmin.AddConfiguration(soConfig);
                soAdmin.StartConfiguration(configName, "ImageServer");

                if (soAdmin.GetConfigurationStatus(configName, "ImageServer").Status == esriConfigurationStatus.esriCSStarted)
                    Console.WriteLine("{0} on {1} has been configured and started.", configName, host);
                else
                    Console.WriteLine("{0} on {1} was configured but can not be started, please investigate.", configName, host);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
            }
        }

        /// <summary>
        /// delete a service
        /// </summary>
        private static void DeleteService()
        {
            try
            {
                if (!ConnectAGS(host)) return;
                IServerObjectAdmin soAdmin = gisServerConnection.ServerObjectAdmin;
                if (!ValidateConfigName(soAdmin, ref configName, host)) return;
                soAdmin.DeleteConfiguration(configName, "ImageServer");
                Console.WriteLine("{0} on {1} was deleted successfully.", configName, host);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
            }
        }

        /// <summary>
        /// start a service
        /// </summary>
        private static void StartService()
        {
            try
            {
                if (!ConnectAGS(host)) return;
                IServerObjectAdmin soAdmin = gisServerConnection.ServerObjectAdmin;
                if (!ValidateConfigName(soAdmin, ref configName, host)) return;
                soAdmin.StartConfiguration(configName, "ImageServer");
                if (soAdmin.GetConfigurationStatus(configName, "ImageServer").Status == esriConfigurationStatus.esriCSStarted)
                    Console.WriteLine("{0} on {1} was started successfully.", configName, host);
                else
                    Console.WriteLine("{0} on {1} couldn't be started, please investigate.", configName, host);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
            }
        }

        /// <summary>
        /// stop a service
        /// </summary>
        private static void StopService()
        {
            try
            {
                if (!ConnectAGS(host)) return;
                IServerObjectAdmin soAdmin = gisServerConnection.ServerObjectAdmin;
                if (!ValidateConfigName(soAdmin, ref configName, host)) return;
                soAdmin.StopConfiguration(configName, "ImageServer");
                if (soAdmin.GetConfigurationStatus(configName, "ImageServer").Status == esriConfigurationStatus.esriCSStopped)
                    Console.WriteLine("{0} on {1} was stopped successfully.", configName, host);
                else
                    Console.WriteLine("{0} on {1} couldn't be stopped, please investigate.", configName, host);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
            }
        }

        /// <summary>
        /// pause a service
        /// </summary>
        private static void PauseService()
        {
            try
            {
                if (!ConnectAGS(host)) return;
                IServerObjectAdmin soAdmin = gisServerConnection.ServerObjectAdmin;
                if (!ValidateConfigName(soAdmin, ref configName, host)) return;
                if ((soAdmin.GetConfigurationStatus(configName, "ImageServer").Status == esriConfigurationStatus.esriCSStopped))
                {
                    Console.WriteLine("{0} on {1} is currently stopped --- not paused.", configName, host);
                    return;
                }
                soAdmin.PauseConfiguration(configName, "ImageServer");
                if (soAdmin.GetConfigurationStatus(configName, "ImageServer").Status == esriConfigurationStatus.esriCSPaused)
                    Console.WriteLine("{0} on {1} was paused successfully.", configName, host);
                else
                    Console.WriteLine("{0} on {1} couldn't be paused, please investigate.", configName, host);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
            }
        }

        /// <summary>
        /// List services
        /// </summary>
        private static void ListServices()
        {
            try
            {
                if (!ConnectAGS(host)) return;
                IServerObjectAdmin soAdmin = gisServerConnection.ServerObjectAdmin;
                IEnumServerObjectConfiguration enumConfigs = soAdmin.GetConfigurations();
                enumConfigs.Reset();
                IServerObjectConfiguration soConfig = enumConfigs.Next();
                Console.WriteLine("ArcGIS Server {0} has the following image services:", host);
                while (soConfig != null)
                {
                    if (soConfig.TypeName == "ImageServer")
                        Console.WriteLine("{0}", soConfig.Name);
                    soConfig = enumConfigs.Next();
                }
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
            }
        }
        #endregion


        #region validation etc.
        /// <summary>
        /// connect to ags server
        /// </summary>
        /// <param name="host">host</param>
        /// <returns>true if connected</returns>
        private static bool ConnectAGS(string host)
        {
            try
            {
                gisServerConnection = new GISServerConnectionClass();
                gisServerConnection.Connect(host);
                return true;
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: Couldn't connect to AGSServer: {0}. Message: {1}", host, exc.Message);
                return false;
            }
        }

        /// <summary>
        /// Validate ConfigName
        /// </summary>
        /// <returns>Convert the config name to the correct case and returns true; if not exist in any cases, returns false </returns>
        private static bool ValidateConfigName(IServerObjectAdmin soAdmin, ref string configName, string host)
        {
            IEnumServerObjectConfiguration enumConfigs = soAdmin.GetConfigurations();
            enumConfigs.Reset();
            IServerObjectConfiguration soConfig = enumConfigs.Next();
            while (soConfig != null)
            {
                if (soConfig.Name.ToUpper() == configName.ToUpper())
                {
                    configName = soConfig.Name;
                    return true;
                }
                soConfig = enumConfigs.Next();
            }
            Console.WriteLine("Configuration {0} on {1} can not be found.", configName, host);
            return false;
        }

        /// <summary>
        /// Validate input parameters
        /// </summary>
        /// <param name="args">args</param>
        /// <returns>validation result</returns>
        private static bool ValidateParams(string[] args)
        {
            //at least two params
            if (args.Length < 2) // at least -o action
            {
                ShowUsage();
                return false;
            }

            // must start with -o
            string[] operations = new string[] { "publish", "delete", "start", "stop", "pause", "list" };
            if ((!args[0].StartsWith("-o")) || (!strInArray(args[1].ToLower(), operations)))
            {
                Console.WriteLine("Incorrect operation");
                ShowUsage();
                return false;
            }

            // for stop/start/pause/list, must contains "-n" and argument length is 4
            if ((args[1].ToLower() == "stop") || (args[1].ToLower() == "start") || (args[1].ToLower() == "pause") || (args[1].ToLower() == "delete"))
            {
                if (!strInArray("-h", args))
                {
                    Console.WriteLine("Missing host server -h");
                    return false;
                }
                if (!strInArray("-n", args))
                {
                    Console.WriteLine("Missing service name switch -n");
                    return false;
                }
                if (args.Length > 6)
                {
                    Console.WriteLine("Too many arguments");
                    return false;
                }
            }
            // for publish, must contains "-d" "-n" and argument length is 6
            if (args[1].ToLower() == "publish")
            {
                if (!strInArray("-d", args))
                {
                    Console.WriteLine("Missing data source switch -d");
                    return false;
                }
                if (!strInArray("-n", args))
                {
                    Console.WriteLine("Missing service name switch -n");
                    return false;
                }
                if (args.Length > 8)
                {
                    Console.WriteLine("Too many arguments");
                    return false;
                }
            }
            // validate each parameter: host, sourcepath, configname
            string[] parameters = new string[] { "-h", "-d", "-n" };
            for (int i = 2; i < args.Length; i++)
            {
                switch (args[i])
                {
                    case "-h":
                        if (i == args.Length - 1)
                        {
                            Console.WriteLine("Missing host parameter, switch -h");
                            return false;
                        }
                        else if (strInArray(args[i + 1], parameters))
                        {
                            Console.WriteLine("Missing host parameter, switch -h");
                            return false;
                        }
                        ++i;
                        break;
                    case "-d":
                        if (i == args.Length - 1)
                        {
                            Console.WriteLine("Missing data source parameter, switch -d");
                            return false;
                        }
                        else if (strInArray(args[i + 1], parameters))
                        {
                            Console.WriteLine("Missing data source parameter, switch -d");
                            return false;
                        }
                        ++i;
                        break;
                    case "-n":
                        if (i == args.Length - 1)
                        {
                            Console.WriteLine("Missing service name parameter, switch -n");
                            return false;
                        }
                        else if (strInArray(args[i + 1], parameters))
                        {
                            Console.WriteLine("Missing service name parameter, switch -n");
                            return false;
                        }
                        ++i;
                        break;
                    default:
                        Console.WriteLine("Incorrect parameter switch: {0} is not a recognized.", args[i]);
                        return false;
                }
            }
            return true;
        }

        /// <summary>
        /// string in array
        /// </summary>
        /// <param name="name"></param>
        /// <param name="nameArray"></param>
        /// <returns></returns>
        private static bool strInArray(string name, string[] nameArray)
        {
            for (int i = 0; i < nameArray.Length; i++)
            {
                if (nameArray[i] == name)
                    return true;
            }
            return false;
        }

        /// <summary>
        /// initialize license
        /// </summary>
        /// <returns>status</returns>
        private static bool InitLicense()
        {
            RuntimeManager.Bind(ProductCode.Desktop);
            IAoInitialize aoInit = new AoInitializeClass();
            string license = System.Environment.GetEnvironmentVariable("ARCLICENSE");
            esriLicenseStatus status = aoInit.Initialize(esriLicenseProductCode.esriLicenseProductCodeArcView);
            if (status != esriLicenseStatus.esriLicenseCheckedOut)
            {
                Console.WriteLine("License initialization  error");
                return false;
            }
            else
                return true;
        }
        #endregion


        #region helper methods
        /// <summary>
        /// Retrieve parameters
        /// </summary>
        /// <param name="args">args</param>
        private static void Retrieve_Params(string[] args)
        {
            for (int i = 2; i < args.Length; i++)
            {
                switch (args[i])
                {
                    case "-h":
                        host = args[++i];
                        break;
                    case "-d":
                        sourcePath = args[++i];
                        break;
                    case "-n":
                        configName = args[++i];
                        break;
                }
            }
        }

        /// <summary>
        /// Get Source Type
        /// </summary>
        /// <param name="sourcePath">path of the data source</param>
        /// <returns>data source type</returns>
        private static esriImageServiceSourceType GetSourceType(string sourcePath)
        {
            if (sourcePath.ToLower().EndsWith(".iscdef"))
                return esriImageServiceSourceType.esriImageServiceSourceTypeCatalog;
            else if (sourcePath.ToLower().EndsWith(".lyr"))
                return esriImageServiceSourceType.esriImageServiceSourceTypeLayer;
            else
            {
                FileInfo fileInfo = new FileInfo(sourcePath);
                OpenRasterDataset(fileInfo.DirectoryName, fileInfo.Name);
                if (rasterDataset is IMosaicDataset)
                    return esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset;
                else
                    return esriImageServiceSourceType.esriImageServiceSourceTypeDataset;
            }
        }

        /// <summary>
        /// Open Raster Dataset
        /// </summary>
        /// <param name="path">path of the dataset</param>
        /// <param name="rasterDSName">name of the dataset</param>        
        private static void OpenRasterDataset(String path, String rasterDSName)
        {
            //this is why the utility user needs access to data source. image service configurations varies among data sources.
            IWorkspaceFactory workspaceFactory = null;
            IWorkspace workspace = null;
            IRasterWorkspaceEx rasterWorkspaceEx = null;
            Type factoryType = null;
            try
            {
                switch (path.Substring(path.Length - 4, 4).ToLower()) // a path can never be shorter than 4 characters, isn't it? c:\a
                {
                    case ".mdb":
                        factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.AccessWorkspaceFactory");
                        workspaceFactory = Activator.CreateInstance(factoryType) as IWorkspaceFactory;
                        workspace = workspaceFactory.OpenFromFile(path, 1);
                        rasterWorkspaceEx = (IRasterWorkspaceEx)workspace;
                        rasterDataset = rasterWorkspaceEx.OpenRasterDataset(rasterDSName);
                        break;
                    case ".gdb":
                        factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory");
                        workspaceFactory = Activator.CreateInstance(factoryType) as IWorkspaceFactory;
                        workspace = workspaceFactory.OpenFromFile(path, 1);
                        rasterWorkspaceEx = (IRasterWorkspaceEx)workspace;
                        rasterDataset = rasterWorkspaceEx.OpenRasterDataset(rasterDSName);
                        break;
                    case ".sde":
                        factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.SdeWorkspaceFactory");
                        workspaceFactory = Activator.CreateInstance(factoryType) as IWorkspaceFactory;
                        workspace = workspaceFactory.OpenFromFile(path, 1);
                        rasterWorkspaceEx = (IRasterWorkspaceEx)workspace;
                        rasterDataset = rasterWorkspaceEx.OpenRasterDataset(rasterDSName);
                        break;
                    default:
                        factoryType = Type.GetTypeFromProgID("esriDataSourcesRaster.RasterWorkspaceFactory");
                        workspaceFactory = Activator.CreateInstance(factoryType) as IWorkspaceFactory;
                        workspace = workspaceFactory.OpenFromFile(path, 1);
                        IRasterWorkspace rasterWorkspace = (IRasterWorkspace)workspace;
                        rasterDataset = rasterWorkspace.OpenRasterDataset(rasterDSName);
                        break;
                }
            }
            catch (Exception)
            {
                throw new ArgumentException("Failed to open source data");
            }
        }

        /// <summary>
        /// Show usage
        /// </summary>
        private static void ShowUsage()
        {
            Console.WriteLine();
            Console.WriteLine("ArcObject Sample: command line image service configuration utility.");
            Console.WriteLine();
            Console.WriteLine("Usage. <>: required parameter; |: pick one.");
            Console.WriteLine("isconfig -o publish -h <host> -d <datapath> -n <configName>");
            Console.WriteLine("isconfig -o <delete|start|stop|pause> -h <host> -n <configName>");
            Console.WriteLine("isconfig -o <list> -h <host>");
        }
        #endregion

    }
}