ArcObjects Library Reference  

ISConfig

About the Publish an image service and set configurations Sample

[C#]

ISConfig.cs

using System;
using System.IO;
using ESRI.ArcGIS;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.GISClient;
using ESRI.ArcGIS.Server;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.DataSourcesRaster;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Runtime.InteropServices;
using System.Web;
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, raster layer); it also have additional features to start,stop,delete image service programmatically.
    /// The user running this utility needs access to data source.
    /// The application can be run locally on AGSServer machine or remotely.
    /// Source data must be accessible by the account that runs ArcGIS Server. Data is not copied to ArcGIS Server through this tool.
    /// CachingScheme/Metadata/thumbnail/iteminfo can't be defined through this tool.
    /// CachingScheme can be done through Caching geoprocessing tools. REST Metadata/thumbnail/iteminfo are not available through this app but can be developed using a similar approach to server admin endpoint
    /// The sample uses Raster API to populate dataset properties (used to construct service configuration), and can eitehr directly invoke rest Admin API to create service; or using AGSClient to create service.
    /// 2. Case sensitivity:  
    /// (1) switches are case sensitive. 
    /// (2) when publish a service, the service name is case sensitive
    /// 3. Usage:
    /// Run from command line environment. Usage. <>: required parameter; |: pick one.
    /// isconfig -o publish -h <host_adminurl> -d <datapath> -n <serviceName>
    /// isconfig -o <delete|start|stop|pause> -h <host> -n <serviceName>
    /// isconfig -o <list> -h <host>
    /// Example 1: isconfig -o publish -h "http://host:6080/arcgis/admin" -u "adminuser" -p "adminpassword" -d \\myserver\data\test.gdb\mdtest -n mdtest
    /// Example 2: isconfig -o stop -h myservername -u "adminuser" -p "adminpassword" -n mdtest
    /// Example 3: isconfig -o list -h myservername -u "adminuser" -p "adminpassword"
    /// </summary>
    class ISConfig
    {
        #region static variables
        private static string sourcePath = ""; //data source path: a raster dataset, a mosaic dataset
        private static string restAdmin = ""; //host admin url e.g. http://host:6080/arcgis/admin
        private static string serviceName = ""; //image service name        
        private static IRasterDataset rasterDataset = null;
        private static IServerObjectAdmin soAdmin = null;
        private static string username = ""; //user name for publisher/admin
        private static string password = ""; //password for publisher/admin
        #endregion

        [STAThread]
        public static void Main(string[] args)
        {
            try
            {
                //args = new string[] { "-o", "publish", "-h", "http://server:6080/arcgis/admin", "-u", "adminuser", "-p", "adminuser", "-d", @"\\server\test\rgb.tif", "-n", "mdtest12356" };
                //args = new string[] { "-o", "list", "-h", "http://server:6080/arcgis/admin", "-u", "adminuser", "-p", "adminuser" };//@"\\server\Images.gdb\mdtest"
                //validation
                if (!ValidateParams(args))
                    return;
                //license           
                if (!InitLicense())
                    return;

                //retrieve parameters
                Retrieve_Params(args);
                string operation = args[1];
                switch (operation.ToLower())
                {
                    case "publish":
                        //CreateISConfig();
                        CreateISConfig_RESTAdmin();
                        break;
                    case "delete":
                        //DeleteService();
                        DeleteService_RESTAdmin();
                        break;
                    case "start":
                        //StartService();
                        StartService_RESTAdmin();
                        break;
                    case "stop":
                        //StopService();
                        StopService_RESTAdmin();
                        break;
                    case "pause":
                        PauseService();
                        break;
                    case "list":
                        //ListServices();
                        ListServices_RESTAdmin();
                        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(restAdmin)) return;

                //get source type
                esriImageServiceSourceType sourceType = GetSourceType(sourcePath);

                //connect to ArcGIS Server and create configuration
                IServerObjectConfiguration5 soConfig = (IServerObjectConfiguration5)soAdmin.CreateConfiguration();

                //set general service parameters
                soConfig.Name = serviceName;
                soConfig.TypeName = "ImageServer";
                soConfig.TargetCluster = "default";

                soConfig.StartupType = esriStartupType.esriSTAutomatic;
                soConfig.IsPooled = true;
                soConfig.IsolationLevel = esriServerIsolationLevel.esriServerIsolationHigh;
                soConfig.MinInstances = 1;
                soConfig.MaxInstances = 2;

                //customize recycle properties
                IPropertySet propertySet_Recycle = soConfig.RecycleProperties;
                propertySet_Recycle.SetProperty("Interval", "24");


                //path to the data
                IPropertySet propertySet = soConfig.Properties;
                IWorkspace workspace = ((IDataset)rasterDataset).Workspace;
                if (workspace.WorkspaceFactory.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace)
                {
                    IWorkspaceName2 wsName2 = ((IDataset)workspace).FullName as IWorkspaceName2;
                    string connString = wsName2.ConnectionString;
                    propertySet.SetProperty("ConnectionString", connString);
                    propertySet.SetProperty("Raster", ((IDataset)rasterDataset).Name);
                }
                else
                    propertySet.SetProperty("Path", sourcePath);
                propertySet.SetProperty("EsriImageServiceSourceType", sourceType.ToString());

                //MIME+URL (virtual directory)
                propertySet.SetProperty("SupportedImageReturnTypes", "MIME+URL");
                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();
                }

                //copy right
                propertySet.SetProperty("CopyRight", "");

                //properties for a mosaic dataset;
                if (sourceType == esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset)
                {
                    IFunctionRasterDataset functionRasterDataset = (IFunctionRasterDataset)rasterDataset;
                    IPropertySet propDefaults = functionRasterDataset.Properties;

                    object names, values;
                    propDefaults.GetAllProperties(out names, out values);
                    List<string> propNames = new List<string>();
                    propNames.AddRange((string[])names);
                    if (propNames.Contains("MaxImageHeight"))
                        propertySet.SetProperty("MaxImageHeight", propDefaults.GetProperty("MaxImageHeight"));//4100
                    if (propNames.Contains("MaxImageWidth"))
                        propertySet.SetProperty("MaxImageWidth", propDefaults.GetProperty("MaxImageWidth"));//15000
                    if (propNames.Contains("AllowedCompressions"))
                        propertySet.SetProperty("AllowedCompressions", propDefaults.GetProperty("AllowedCompressions"));//"None,JPEG,LZ77,LERC"
                    if (propNames.Contains("DefaultResamplingMethod"))
                        propertySet.SetProperty("DefaultResamplingMethod", propDefaults.GetProperty("DefaultResamplingMethod"));//0
                    if (propNames.Contains("DefaultCompressionQuality"))
                        propertySet.SetProperty("DefaultCompressionQuality", propDefaults.GetProperty("DefaultCompressionQuality"));//75
                    if (propNames.Contains("MaxRecordCount"))
                        propertySet.SetProperty("MaxRecordCount", propDefaults.GetProperty("MaxRecordCount"));//500
                    if (propNames.Contains("MaxMosaicImageCount"))
                        propertySet.SetProperty("MaxMosaicImageCount", propDefaults.GetProperty("MaxMosaicImageCount"));//20
                    if (propNames.Contains("MaxDownloadSizeLimit"))
                        propertySet.SetProperty("MaxDownloadSizeLimit", propDefaults.GetProperty("MaxDownloadSizeLimit"));//20
                    if (propNames.Contains("MaxDownloadImageCount"))
                        propertySet.SetProperty("MaxDownloadImageCount", propDefaults.GetProperty("MaxDownloadImageCount"));//20
                    if (propNames.Contains("AllowedFields"))
                        propertySet.SetProperty("AllowedFields", propDefaults.GetProperty("AllowedFields"));//"Name,MinPS,MaxPS,LowPS,HighPS,CenterX,CenterY"
                    if (propNames.Contains("AllowedMosaicMethods"))
                        propertySet.SetProperty("AllowedMosaicMethods", propDefaults.GetProperty("AllowedMosaicMethods"));//"Center,NorthWest,LockRaster,ByAttribute,Nadir,Viewpoint,Seamline"
                    if (propNames.Contains("AllowedItemMetadata"))
                        propertySet.SetProperty("AllowedItemMetadata", propDefaults.GetProperty("AllowedItemMetadata"));//"Full"
                    if (propNames.Contains("AllowedMensurationCapabilities"))
                        propertySet.SetProperty("AllowedMensurationCapabilities", propDefaults.GetProperty("AllowedMensurationCapabilities"));//"Full"
                    if (propNames.Contains("DefaultCompressionTolerance"))
                        propertySet.SetProperty("DefaultCompressionTolerance", propDefaults.GetProperty("DefaultCompressionTolerance"));//"0.01" LERC compression
                    //propertySet.SetProperty("RasterFunctions", @"\\server\dir\rft1.rft.xml,\\server\dir\rft2.rft.xml");//"put raster function templates here, the first one is applied to exportimage request by default"
                    //propertySet.SetProperty("RasterTypes", @"Raster Dataset,\\server\dir\art1.art.xml,\\server\dir\art2.art");//"put raster types here"
                    //propertySet.SetProperty("DynamicImageWorkspace", @"\\server\dynamicImageDir"); //put the workspace that holds uploaded imagery here
                    //propertySet.SetProperty("supportsOwnershipBasedAccessControl", true); //ownership based access control
                    //propertySet.SetProperty("AllowOthersToUpdate", true); //allow others to update a catalog item
                    //propertySet.SetProperty("AllowOthersToDelete", true); //allow others to delete a catalog item
                    //propertySet.SetProperty("DownloadDir", ""); //put the download directory here
                    //propertySet.SetProperty("VirutalDownloadDir", ""); //put the virtual download directory here
                }
                else
                {
                    propertySet.SetProperty("MaxImageHeight", 4100);
                    propertySet.SetProperty("MaxImageWidth", 15000);
                    propertySet.SetProperty("AllowedCompressions", "None,JPEG,LZ77");
                    propertySet.SetProperty("DefaultResamplingMethod", 0);
                    propertySet.SetProperty("DefaultCompressionQuality", 75);//for jpg compression
                    propertySet.SetProperty("DefaultCompressionTolerance", 0.01);//for LERC compression                 
                    //    rasterDataset = OpenRasterDataset(sourcePath);
                    IMensuration measure = new MensurationClass();
                    measure.Raster = ((IRasterDataset2)rasterDataset).CreateFullRaster();
                    string mensurationCaps = "";
                    if (measure.CanMeasure)
                        mensurationCaps = "Basic";
                    if (measure.CanMeasureHeightBaseToTop)
                        mensurationCaps += ",Base-Top Height";
                    if (measure.CanMeasureHeightBaseToTopShadow)
                        mensurationCaps += ",Base-Top Shadow Height";
                    if (measure.CanMeasureHeightTopToTopShadow)
                        mensurationCaps += ",Top-Top Shadow Height";
                    propertySet.SetProperty("AllowedMensurationCapabilities", mensurationCaps); //set mensuration here
                }

                //not cached
                propertySet.SetProperty("IsCached", false);
                propertySet.SetProperty("IgnoreCache", true);
                propertySet.SetProperty("UseLocalCacheDir", false);
                propertySet.SetProperty("ClientCachingAllowed", false);

                //propertySet.SetProperty("DEM", ""); //put the elevation raster dataset or service for 3D mensuration, may need to add 3D to AllowedMensurationCapabilities

                //convert colormap to RGB or not
                propertySet.SetProperty("ColormapToRGB", false);

                //whether to return jpgs for all jpgpng request or not
                propertySet.SetProperty("ReturnJPGPNGAsJPG", false);

                //allow server to process client defined function
                propertySet.SetProperty("AllowFunction", true); //allow raster function


                //capabilities
                if (sourceType == esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset)
                    soConfig.Info.SetProperty("Capabilities", "Image,Catalog,Metadata,Mensuration");
                //Full set: Image,Catalog,Metadata,Download,Pixels,Edit,Mensuration
                else
                    soConfig.Info.SetProperty("Capabilities", "Image,Metadata,Mensuration");

                //enable wcs, assume data has spatial reference
                soConfig.set_ExtensionEnabled("WCSServer", true);
                IPropertySet wcsInfo = new PropertySetClass();
                wcsInfo.SetProperty("WebEnabled", "true");
                soConfig.set_ExtensionInfo("WCSServer", wcsInfo);
                IPropertySet propertySetWCS = new PropertySetClass();
                propertySetWCS.SetProperty("CustomGetCapabilities", false);
                propertySetWCS.SetProperty("PathToCustomGetCapabilitiesFiles", "");
                soConfig.set_ExtensionProperties("WCSServer", propertySetWCS);

                //enable wms
                soConfig.set_ExtensionEnabled("WMSServer", true);
                IPropertySet wmsInfo = new PropertySetClass();
                wmsInfo.SetProperty("WebEnabled", "true");
                soConfig.set_ExtensionInfo("WMSServer", wmsInfo);
                IPropertySet propertySetWMS = new PropertySetClass();
                propertySetWMS.SetProperty("name", "WMS"); //set other properties here
                soConfig.set_ExtensionProperties("WMSServer", propertySetWMS);


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

                if (soAdmin.GetConfigurationStatus(serviceName, "ImageServer").Status == esriConfigurationStatus.esriCSStarted)
                    Console.WriteLine("{0} on {1} has been configured and started.", serviceName, restAdmin);
                else
                    Console.WriteLine("{0} on {1} was configured but can not be started, please investigate.", serviceName, restAdmin);

                if (rasterDataset != null)
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(rasterDataset);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
            }
        }

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

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

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

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

        /// <summary>
        /// List services
        /// </summary>
        private static void ListServices()
        {
            try
            {
                if (!ConnectAGS(restAdmin)) return;
                IEnumServerObjectConfiguration enumConfigs = soAdmin.GetConfigurations();
                enumConfigs.Reset();
                IServerObjectConfiguration soConfig = enumConfigs.Next();
                Console.WriteLine("ArcGIS Server {0} has the following image services:", restAdmin);
                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
            {
                IPropertySet propertySet = new PropertySetClass();
                propertySet.SetProperty("url", host);
                propertySet.SetProperty("ConnectionMode", esriAGSConnectionMode.esriAGSConnectionModePublisher);
                propertySet.SetProperty("ServerType", esriAGSServerType.esriAGSServerTypeDiscovery);
                propertySet.SetProperty("user", username);
                propertySet.SetProperty("password", password);
                propertySet.SetProperty("ALLOWINSECURETOKENURL", true);

                IAGSServerConnectionName3 connectName = new AGSServerConnectionNameClass() as IAGSServerConnectionName3;
                connectName.ConnectionProperties = propertySet;

                IAGSServerConnectionAdmin agsAdmin = ((IName)connectName).Open() as IAGSServerConnectionAdmin;
                soAdmin = agsAdmin.ServerObjectAdmin;
                return true;
            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: Couldn't connect to AGSServer: {0}. Message: {1}", host, exc.Message);
                return false;
            }
        }

        /// <summary>
        /// Validate ServiceName
        /// </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 ValidateServiceName(IServerObjectAdmin soAdmin, ref string serviceName, string host)
        {
            IEnumServerObjectConfiguration enumConfigs = soAdmin.GetConfigurations();
            enumConfigs.Reset();
            IServerObjectConfiguration soConfig = enumConfigs.Next();
            while (soConfig != null)
            {
                if (soConfig.Name.ToUpper() == serviceName.ToUpper())
                {
                    serviceName = soConfig.Name;
                    return true;
                }
                soConfig = enumConfigs.Next();
            }
            Console.WriteLine("Configuration {0} on {1} can not be found.", serviceName, 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 == 0)
            {
                ShowUsage();
                Console.WriteLine("press any key to continue ...");
                Console.ReadKey();
                return false;
            }
            else 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 (!strInArray("-u", args))
                {
                    Console.WriteLine("Missing admin/publisher username switch -u");
                    return false;
                }
                if (!strInArray("-p", args))
                {
                    Console.WriteLine("Missing admin/publisher name switch -p");
                    return false;
                }
                //if (args.Length > 8)
                //{
                //    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 (!strInArray("-u", args))
                {
                    Console.WriteLine("Missing admin/publisher username switch -u");
                    return false;
                }
                if (!strInArray("-p", args))
                {
                    Console.WriteLine("Missing admin/publisher name switch -p");
                    return false;
                }
                //if (args.Length > 12)
                //{
                //    Console.WriteLine("Too many arguments");
                //    return false;
                //}
            }
            // validate each parameter: host, sourcepath, configname
            string[] parameters = new string[] { "-h", "-d", "-n", "-u", "-p" };
            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;
                    case "-u":
                        if (i == args.Length - 1)
                        {
                            Console.WriteLine("Missing admin/publisher username parameter, switch -u");
                            return false;
                        }
                        else if (strInArray(args[i + 1], parameters))
                        {
                            Console.WriteLine("Missing admin/publisher username parameter, switch -u");
                            return false;
                        }
                        ++i;
                        break;
                    case "-p":
                        if (i == args.Length - 1)
                        {
                            Console.WriteLine("Missing admin/publisher password parameter, switch -p");
                            return false;
                        }
                        else if (strInArray(args[i + 1], parameters))
                        {
                            Console.WriteLine("Missing admin/publisher password parameter, switch -p");
                            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();
            esriLicenseStatus status = aoInit.Initialize(esriLicenseProductCode.esriLicenseProductCodeBasic);
            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":
                        restAdmin = args[++i];
                        break;
                    case "-d":
                        sourcePath = args[++i];
                        break;
                    case "-n":
                        serviceName = args[++i];
                        break;
                    case "-u":
                        username = args[++i];
                        break;
                    case "-p":
                        password = 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(".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 ".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 publishing and configuration utility (10.1 ArcGIS Server). Data is not copied to server using this tool. source data must be accessible by ArcGIS Server running account. CachingScheme can't be defined through this tool but can be done through Caching geoprocessing tools. REST Metadata/thumbnail/iteminfo resource are not available through this app but can be developed using a similar approach to server admin endpoint.");
            Console.WriteLine();
            Console.WriteLine("Usage. <>: required parameter; |: pick one.");
            Console.WriteLine("isconfig -o publish -h <host_admin_url> -u <adminuser> -p <adminpassword> -d <datapath> -n <serviceName>");
            Console.WriteLine("isconfig -o <delete|start|stop> -h <host_admin_url> -u <adminuser> -p <adminpassword> -n <serviceName>");
            Console.WriteLine("isconfig -o <list> -h <host_admin_url> -u <adminuser> -p <adminpassword>");
            Console.WriteLine("e.g. isconfig -o list -h http://myserver:6080/arcgis/admin -u username -p password");
        }
        #endregion

        #region REST Admin based http requests
        /// <summary>
        /// Generate a token
        /// </summary>
        /// <param name="restAdmin">REST admin url: http://server:port/arcigs/admin</param>
        /// <returns>A token that has default expiration time</returns>
        public static string GenerateAGSToken_RESTAdmin()
        {
            try
            {
                string loginUrl = restAdmin + "/generateToken";
                WebRequest request = WebRequest.Create(loginUrl);
                request.Method = "POST";
                string credential = "username=" + username + "&password=" + password + "&client=requestip&expiration=&f=json";
                byte[] content = Encoding.UTF8.GetBytes(credential);
                request.ContentLength = content.Length;
                request.ContentType = "application/x-www-form-urlencoded";
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(content, 0, content.Length);
                requestStream.Close();
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);
                string result = reader.ReadToEnd();
                int index1 = result.IndexOf("token\":\"") + "token\":\"".Length;
                int index2 = result.IndexOf("\"", index1);
                //Dictionary<string, object> dictResult = DeserializeJSON(result, true);
                string token = result.Substring(index1, index2 - index1);
                return token;
            }
            catch { return ""; }
        }

        /// <summary>
        /// Create arcgis server folder
        /// </summary>
        /// <param name="restAdmin">REST admin url, e.g. http://server:port/arcgis/admin</param>
        /// <param name="folderName">Folder name</param>
        /// <param name="description">Description of the folder</param>
        /// <returns>True if successfully created</returns>
        private static bool CreateServerFolder_RESTAdmin(string folderName, string description)
        {
            try
            {
                string token = GenerateAGSToken_RESTAdmin();
                restAdmin = restAdmin.EndsWith("/") ? restAdmin.Substring(0, restAdmin.Length - 1) : restAdmin;
                string folderUrl = restAdmin + "/services/" + folderName + "?f=json&token=" + token;
                WebRequest request = WebRequest.Create(folderUrl);
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);
                string result = reader.ReadToEnd();
                if (!result.Contains("error"))
                    return true;
                else
                {
                    string createFolderUrl = restAdmin + "/services/createFolder";
                    request = WebRequest.Create(createFolderUrl);
                    string postcontent = string.Format("folderName={0}&description={1}&f=pjson&token={2}", folderName, description, token);
                    Byte[] content = Encoding.UTF8.GetBytes(postcontent);
                    request.ContentLength = content.Length;
                    //((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
                    request.ContentType = "application/x-www-form-urlencoded";
                    request.Method = "POST";
                    Stream requestStream = request.GetRequestStream();
                    requestStream.Write(content, 0, content.Length);
                    requestStream.Close();
                    response = request.GetResponse();
                    responseStream = response.GetResponseStream();
                    reader = new StreamReader(responseStream);
                    result = reader.ReadToEnd();
                    return result.Contains("success");
                }
            }
            catch { return false; }
        }
        private static void GetServerDirectory_RESTAdmin(string dirType, out string physicalPath, out string virtualPath)
        {
            physicalPath = "";
            virtualPath = "";
            try
            {
                string token = GenerateAGSToken_RESTAdmin();
                restAdmin = restAdmin.EndsWith("/") ? restAdmin.Substring(0, restAdmin.Length - 1) : restAdmin;
                string directoryAlias = dirType.ToString().ToLower().Replace("esrisdtype", "arcgis");
                string directoryUrl = restAdmin + "/system/directories/" + directoryAlias + "?f=json&token=" + token;
                WebRequest request = WebRequest.Create(directoryUrl);
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);
                string result = reader.ReadToEnd();
                try
                {
                    int index = result.IndexOf(dirType);
                    int index1 = result.IndexOf("physicalPath\":\"", index) + "physicalPath\":\"".Length;
                    int index2 = result.IndexOf("\"", index1);
                    physicalPath = result.Substring(index1, index2 - index1);

                    index1 = result.IndexOf("virtualPath\":\"", index) + "virtualPath\":\"".Length;
                    index2 = result.IndexOf("\"", index1);
                    virtualPath = result.Substring(index1, index2 - index1);
                }
                catch { }
            }
            catch { }
        }
        /// <summary>
        /// Delete Service
        /// </summary>
        /// <param name="restAdmin">REST admin url, e.g. http://server:port/arcgis/admin</param>
        /// <param name="serviceName">Service Name</param>
        /// <param name="serviceType">Server Type, e.g. ImageServer, MapServer, GeoDataServer, GeoprocessingServer, GeometryServer, etc</param>
        /// <returns>True if successfully deleted</returns>
        public static bool DeleteService_RESTAdmin()
        {
            try
            {
                string token = GenerateAGSToken_RESTAdmin();
                restAdmin = restAdmin.EndsWith("/") ? restAdmin.Substring(0, restAdmin.Length - 1) : restAdmin;
                string serviceUrl = restAdmin + "/services/" + serviceName + "." + "ImageServer" + "/delete";
                WebRequest request = WebRequest.Create(serviceUrl);
                string postcontent = "f=pjson&token=" + token;
                Byte[] content = Encoding.UTF8.GetBytes(postcontent);
                request.ContentLength = content.Length;
                //((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
                request.ContentType = "application/x-www-form-urlencoded";
                request.Method = "POST";
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(content, 0, content.Length);
                requestStream.Close();
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);
                string result = reader.ReadToEnd();
                Console.WriteLine("delete service {0}, result: {1}", serviceName, result);
                return result.Contains("success");
            }
            catch { return false; }
        }

        public static bool StartService_RESTAdmin()
        {
            try
            {
                string token = GenerateAGSToken_RESTAdmin();
                restAdmin = restAdmin.EndsWith("/") ? restAdmin.Substring(0, restAdmin.Length - 1) : restAdmin;
                string serviceUrl = restAdmin + "/services/" + serviceName + "." + "ImageServer" + "/start";
                WebRequest request = WebRequest.Create(serviceUrl);
                string postcontent = "f=pjson&token=" + token;
                Byte[] content = Encoding.UTF8.GetBytes(postcontent);
                request.ContentLength = content.Length;
                //((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
                request.ContentType = "application/x-www-form-urlencoded";
                request.Method = "POST";
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(content, 0, content.Length);
                requestStream.Close();
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);
                string result = reader.ReadToEnd();
                Console.WriteLine("start service {0}, result: {1}", serviceName, result);
                return result.Contains("success");
            }
            catch { return false; }
        }

        public static bool StopService_RESTAdmin()
        {
            try
            {
                string token = GenerateAGSToken_RESTAdmin();
                restAdmin = restAdmin.EndsWith("/") ? restAdmin.Substring(0, restAdmin.Length - 1) : restAdmin;
                string serviceUrl = restAdmin + "/services/" + serviceName + "." + "ImageServer" + "/stop";
                WebRequest request = WebRequest.Create(serviceUrl);
                string postcontent = "f=pjson&token=" + token;
                Byte[] content = Encoding.UTF8.GetBytes(postcontent);
                request.ContentLength = content.Length;
                //((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
                request.ContentType = "application/x-www-form-urlencoded";
                request.Method = "POST";
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(content, 0, content.Length);
                requestStream.Close();
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);
                string result = reader.ReadToEnd();
                Console.WriteLine("stop service {0}, result: {1}", serviceName, result);
                return result.Contains("success");
            }
            catch { return false; }
        }
        public static void ListServices_RESTAdmin()
        {
            Console.WriteLine("List of image services: ");
            ListServices_RESTAdmin(restAdmin + "/services", "");
        }
        public static void ListServices_RESTAdmin(string root, string folder)
        {
            try
            {
                string token = GenerateAGSToken_RESTAdmin();
                restAdmin = restAdmin.EndsWith("/") ? restAdmin.Substring(0, restAdmin.Length - 1) : restAdmin;
                string serviceUrl = root + "/" + folder;
                WebRequest request = WebRequest.Create(serviceUrl);
                string postcontent = "f=json&token=" + token;
                Byte[] content = Encoding.UTF8.GetBytes(postcontent);
                request.ContentLength = content.Length;
                //((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
                request.ContentType = "application/x-www-form-urlencoded";
                request.Method = "POST";
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(content, 0, content.Length);
                requestStream.Close();
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);
                string result = reader.ReadToEnd();
                int indexfolder1 = result.IndexOf("folders\":[");
                if (indexfolder1 != -1)
                {
                    indexfolder1 += "folders\":[".Length;
                    int indexfolder2 = result.IndexOf("]", indexfolder1);
                    string folderlist = result.Substring(indexfolder1, indexfolder2 - indexfolder1);
                    string[] folders = folderlist.Replace("\"", "").Split(',');
                    foreach (string subfolder in folders)
                        ListServices_RESTAdmin(serviceUrl, subfolder);
                }


                int index = result.IndexOf("services");
                while (index > 0)
                {
                    try
                    {
                        int index1 = result.IndexOf("folderName\":\"", index);
                        if (index1 == -1)
                            break;
                        index1 += "folderName\":\"".Length;
                        int index2 = result.IndexOf("\"", index1);
                        string folderName = result.Substring(index1, index2 - index1);

                        index1 = result.IndexOf("serviceName\":\"", index2) + "serviceName\":\"".Length;
                        index2 = result.IndexOf("\"", index1);
                        string serviceName = result.Substring(index1, index2 - index1);

                        index1 = result.IndexOf("type\":\"", index2) + "type\":\"".Length;
                        index2 = result.IndexOf("\"", index1);
                        string serviceType = result.Substring(index1, index2 - index1);
                        if (serviceType == "ImageServer")
                        {
                            if (folderName == "/") //root
                                Console.WriteLine(serviceName);
                            else
                                Console.WriteLine(folderName + "/" + serviceName);
                        }
                        index = index2;
                    }
                    catch { }
                }
            }
            catch { }
        }
        /// <summary>
        /// create image service
        /// </summary>
        /// <param name="restAdmin">host machine name (windows or linux)</param>
        /// <param name="sourcePath">data source path, must be windows path (linux path is constructed automaticlly by windows path)</param>
        /// <param name="serviceName">configuration name</param>
        /// <param name="createImageServiceParams">Cration parameters, e.g. raster functions, colormaptorgb, raster types, dem, dynamicimageworkspace, customized propertyset etc</param>
        /// <returns>true if created successfully</returns>
        public static bool CreateISConfig_RESTAdmin()
        {
            //string restAdmin, string username, string password, string sourcePath, string serviceName
            try
            {
                esriImageServiceSourceType sourceType = GetSourceType(sourcePath);

                string serviceType = "ImageServer";
                //DeleteService_RESTAdmin();
                restAdmin = restAdmin.EndsWith("/") ? restAdmin.Substring(0, restAdmin.Length - 1) : restAdmin;
                string serviceFolder = "";
                if (serviceName.Contains("/"))
                {
                    serviceFolder = serviceName.Substring(0, serviceName.IndexOf("/"));
                    CreateServerFolder_RESTAdmin(serviceFolder, "");
                    serviceName = serviceName.Substring(serviceFolder.Length + 1, serviceName.Length - serviceFolder.Length - 1);
                }
                string createServiceUrl = "";
                if (serviceFolder == "")
                    createServiceUrl = restAdmin + "/services/createService";
                else
                    createServiceUrl = restAdmin + "/services/" + serviceFolder + "/createService";
                //createServiceUrl = "http://wenxue:6080/arcgis/admin/services/createService";
                WebRequest request = WebRequest.Create(createServiceUrl);

                //DataSourceIsReadOnly                                                                                                                                                                                                                                                                                                                                                                                                            
                StringBuilder sBuilder = new StringBuilder();
                sBuilder.Append("{");
                sBuilder.AppendFormat("{0}: {1},", QuoteString("serviceName"), QuoteString(serviceName));
                sBuilder.AppendFormat("{0}: {1},", QuoteString("type"), QuoteString(serviceType));
                sBuilder.AppendFormat("{0}: {1},", QuoteString("description"), QuoteString(""));

                sBuilder.AppendFormat("{0}: {1},", QuoteString("clusterName"), QuoteString("default"));
                sBuilder.AppendFormat("{0}: {1},", QuoteString("minInstancesPerNode"), 1);
                sBuilder.AppendFormat("{0}: {1},", QuoteString("maxInstancesPerNode"), 2);
                sBuilder.AppendFormat("{0}: {1},", QuoteString("maxWaitTime"), 10000);
                sBuilder.AppendFormat("{0}: {1},", QuoteString("maxIdleTime"), 1800);
                sBuilder.AppendFormat("{0}: {1},", QuoteString("maxUsageTime"), 600);
                sBuilder.AppendFormat("{0}: {1},", QuoteString("loadBalancing"), QuoteString("ROUND_ROBIN"));
                sBuilder.AppendFormat("{0}: {1},", QuoteString("isolationLevel"), QuoteString("HIGH"));
                sBuilder.AppendFormat("{0}: {1},", QuoteString("configuredState"), QuoteString("STARTED"));

                string webCapabilities = "";

                if (sourceType == esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset)
                    webCapabilities = "Image,Catalog,Metadata,Mensuration";//full list "Image,Catalog,Metadata,Download,Pixels,Edit,Mensuration"
                else
                    webCapabilities = "Image,Metadata,Mensuration";
                sBuilder.AppendFormat("{0}: {1},", QuoteString("capabilities"), QuoteString(webCapabilities));


                sBuilder.AppendFormat("{0}: {1}", QuoteString("properties"), "{");
                sBuilder.AppendFormat("{0}: {1},", QuoteString("supportedImageReturnTypes"), QuoteString("MIME+URL"));

                IWorkspace workspace = ((IDataset)rasterDataset).Workspace;
                if (workspace.WorkspaceFactory.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace)
                {
                    IWorkspaceName2 wsName2 = ((IDataset)workspace).FullName as IWorkspaceName2;
                    string connString = wsName2.ConnectionString;
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("connectionString"), QuoteString(connString));
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("raster"), QuoteString(((IDataset)rasterDataset).Name));
                }
                else
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("path"), QuoteString(sourcePath.Replace("\\", "\\\\")));

                sBuilder.AppendFormat("{0}: {1},", QuoteString("esriImageServiceSourceType"), QuoteString(sourceType.ToString()));

                string outputDir = "";
                string virtualDir = "";

                GetServerDirectory_RESTAdmin("arcgisoutput", out outputDir, out virtualDir);

                string cacheDir = "";
                string virtualCacheDir = "";
                GetServerDirectory_RESTAdmin("arcgisoutput", out cacheDir, out virtualCacheDir);


                if (outputDir != "")
                {
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("outputDir"), QuoteString(outputDir));
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("virtualOutputDir"), QuoteString(virtualDir));//http://istest2:6080/arcgis/server/arcgisoutput"));
                    //sBuilder.AppendFormat("{0}: {1},", QuoteString("dynamicImageWorkspace"), QuoteString(@"D:\UploadDir"));                    
                }
                //if (cacheDir != "")
                //{
                //    sBuilder.AppendFormat("{0}: {1},", QuoteString("cacheDir"), QuoteString(cacheDir));
                //    sBuilder.AppendFormat("{0}: {1},", QuoteString("virtualCacheDir"), QuoteString(virtualCacheDir));//http://istest2:6080/arcgis/server/arcgisoutput"));                    
                //}
                sBuilder.AppendFormat("{0}: {1},", QuoteString("copyright"), QuoteString(""));

                //properties for a mosaic Dataset;
                if (sourceType == esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset)
                {
                    IFunctionRasterDataset functionRasterDataset = (IFunctionRasterDataset)rasterDataset;
                    IPropertySet propDefaults = functionRasterDataset.Properties;
                    object names, values;
                    propDefaults.GetAllProperties(out names, out values);
                    List<string> propNames = new List<string>();
                    propNames.AddRange((string[])names);
                    if (propNames.Contains("AllowedCompressions"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedCompressions"), QuoteString(propDefaults.GetProperty("AllowedCompressions").ToString()));//string
                    if (propNames.Contains("MaxImageHeight"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("maxImageHeight"), QuoteString(propDefaults.GetProperty("MaxImageHeight").ToString()));//should be int     
                    if (propNames.Contains("MaxImageWidth"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("maxImageWidth"), QuoteString(propDefaults.GetProperty("MaxImageWidth").ToString()));//should be int
                    if (propNames.Contains("DefaultResamplingMethod"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultResamplingMethod"), QuoteString(propDefaults.GetProperty("DefaultResamplingMethod").ToString()));//should be int
                    if (propNames.Contains("DefaultCompressionQuality"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultCompressionQuality"), QuoteString(propDefaults.GetProperty("DefaultCompressionQuality").ToString()));//should be int
                    if (propNames.Contains("MaxRecordCount"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("maxRecordCount"), QuoteString(propDefaults.GetProperty("MaxRecordCount").ToString()));//should be int
                    if (propNames.Contains("MaxMosaicImageCount"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("maxMosaicImageCount"), QuoteString(propDefaults.GetProperty("MaxMosaicImageCount").ToString()));//should be int
                    if (propNames.Contains("MaxDownloadImageCount"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("maxDownloadImageCount"), QuoteString(propDefaults.GetProperty("MaxDownloadImageCount").ToString()));//should be int
                    if (propNames.Contains("MaxDownloadSizeLimit"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("MaxDownloadSizeLimit"), QuoteString(propDefaults.GetProperty("MaxDownloadSizeLimit").ToString()));//should be int
                    if (propNames.Contains("AllowedFields"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedFields"), QuoteString(propDefaults.GetProperty("AllowedFields").ToString()));//string
                    if (propNames.Contains("AllowedMosaicMethods"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedMosaicMethods"), QuoteString(propDefaults.GetProperty("AllowedMosaicMethods").ToString()));//string
                    if (propNames.Contains("AllowedItemMetadata"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedItemMetadata"), QuoteString(propDefaults.GetProperty("AllowedItemMetadata").ToString()));//string
                    if (propNames.Contains("AllowedMensurationCapabilities"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("AllowedMensurationCapabilities"), QuoteString(propDefaults.GetProperty("AllowedMensurationCapabilities").ToString()));//string
                    if (propNames.Contains("DefaultCompressionTolerance"))
                        sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultCompressionTolerance"), QuoteString(propDefaults.GetProperty("DefaultCompressionTolerance").ToString()));//string                    
                    //sBuilder.AppendFormat("{0}: {1},", QuoteString("downloadDir"), QuoteString(@"c:\temp"));//string
                    //sBuilder.AppendFormat("{0}: {1},", QuoteString("virutalDownloadDir"), QuoteString(@"http://localhost/temp");//string
                }
                else if (sourceType != esriImageServiceSourceType.esriImageServiceSourceTypeCatalog) //not iscdef
                {
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedCompressions"), QuoteString("None,JPEG,LZ77"));
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("maxImageHeight"), QuoteString("4100"));//should be int     
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("maxImageWidth"), QuoteString("15000"));//should be int
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultResamplingMethod"), QuoteString("0"));//should be int
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultCompressionQuality"), QuoteString("75"));//should be int
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultCompressionTolerance"), QuoteString("0.01"));//should be int
                    IMensuration measure = new MensurationClass();
                    measure.Raster = ((IRasterDataset2)rasterDataset).CreateFullRaster();
                    string mensurationCaps = "";
                    if (measure.CanMeasure)
                        mensurationCaps = "Basic";
                    if (measure.CanMeasureHeightBaseToTop)
                        mensurationCaps += ",Base-Top Height";
                    if (measure.CanMeasureHeightBaseToTopShadow)
                        mensurationCaps += ",Base-Top Shadow Height";
                    if (measure.CanMeasureHeightTopToTopShadow)
                        mensurationCaps += ",Top-Top Shadow Height";
                    sBuilder.AppendFormat("{0}: {1},", QuoteString("AllowedMensurationCapabilities"), QuoteString(mensurationCaps));//string
                }

                //sBuilder.AppendFormat("{0}: {1},", QuoteString("dEM"), QuoteString(@"c:\elevation\elevation.tif"));                
                //sBuilder.AppendFormat("{0}: {1},", QuoteString("supportsOwnershipBasedAccessControl"), QuoteString("true"));
                //sBuilder.AppendFormat("{0}: {1},", QuoteString("allowOthersToUpdate"), QuoteString("true"));               
                //sBuilder.AppendFormat("{0}: {1},", QuoteString("allowOthersToDelete"), QuoteString("true"));
                //sBuilder.AppendFormat("{0}: {1},", QuoteString("cacheOnDemand"), QuoteString("false"));
                //sBuilder.AppendFormat("{0}: {1},", QuoteString("isCached"), QuoteString("false"));
                //sBuilder.AppendFormat("{0}: {1},", QuoteString("ignoreCache"), QuoteString("true"));
                //sBuilder.AppendFormat("{0}: {1},", QuoteString("useLocalCacheDir"), QuoteString("false"));
                //sBuilder.AppendFormat("{0}: {1},", QuoteString("clientCachingAllowed"), QuoteString("false"));


                sBuilder.AppendFormat("{0}: {1},", QuoteString("colormapToRGB"), QuoteString("false"));
                sBuilder.AppendFormat("{0}: {1},", QuoteString("returnJPGPNGAsJPG"), QuoteString("false"));
                sBuilder.AppendFormat("{0}: {1},", QuoteString("allowFunction"), QuoteString("true"));
                string rasterFunctions = "";
                sBuilder.AppendFormat("{0}: {1},", QuoteString("rasterFunctions"), QuoteString(rasterFunctions).Replace("\\", "\\\\"));
                string rasterTypes = "";
                sBuilder.AppendFormat("{0}: {1}", QuoteString("rasterTypes"), QuoteString(rasterTypes).Replace("\\", "\\\\"));

                sBuilder.Append("},");
                bool enableWCS = true;
                bool enableWMS = true;
                sBuilder.AppendFormat("{0}: {1}", QuoteString("extensions"), "[{\"typeName\":\"WCSServer\",\"enabled\":\"" + enableWCS + "\",\"capabilities\":null,\"properties\":{}},{\"typeName\":\"WMSServer\",\"enabled\":\"" + enableWMS + "\",\"capabilities\":null,\"properties\":{\"title\":\"WMS\",\"name\":\"WMS\",\"inheritLayerNames\":\"false\"}}");
                sBuilder.Append("],");
                sBuilder.AppendFormat("{0}: {1}", QuoteString("datasets"), "[]");
                sBuilder.Append("}");
                string postcontent = HttpUtility.UrlEncode(sBuilder.ToString());
                string token = GenerateAGSToken_RESTAdmin();
                postcontent = "service=" + postcontent + "&startAfterCreate=on&f=pjson&token=" + token;
                Byte[] content = Encoding.UTF8.GetBytes(postcontent);
                request.ContentLength = content.Length;
                request.ContentType = "application/x-www-form-urlencoded";
                request.Method = "POST";
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(content, 0, content.Length);
                requestStream.Close();
                WebResponse response = request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(responseStream);
                string result = reader.ReadToEnd();
                Console.WriteLine("create service:" + serviceName + " result:" + result);
                //wait for 5 seconds to reduce latency issue
                //System.Threading.Thread.Sleep(5000);
                return result.Contains("success");
            }
            catch (Exception exc) { Console.WriteLine(exc.Message); return false; }
        }
        private static string QuoteString(string input)
        {
            return "\"" + input + "\"";
        }
        private static string DeQuoteString(string input)
        {
            if (input.StartsWith("\""))
                return input.Substring(1, input.Length - 2).Trim();
            else
                return input;
        }

        #endregion

    }
}

[Visual Basic .NET]

ISConfig.vb

Imports System.IO
Imports ESRI.ArcGIS
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.GISClient
Imports ESRI.ArcGIS.Server
Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.DataSourcesGDB
Imports ESRI.ArcGIS.DataSourcesRaster
Imports System.Collections.Generic
Imports System.Net
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Web
''' <summary>
''' 1. Description:
''' This sample demonstrate how to create an image service and set configurations based on data source types (raster dataset, mosaic dataset, raster layer); it also have additional features to start,stop,delete image service programmatically.
''' The user running this utility needs access to data source.
''' The application can be run locally on AGSServer machine or remotely.
''' Source data must be accessible by the account that runs ArcGIS Server. Data is not copied to ArcGIS Server through this tool.
''' CachingScheme/Metadata/thumbnail/iteminfo can't be defined through this tool.
''' CachingScheme can be done through Caching geoprocessing tools. REST Metadata/thumbnail/iteminfo are not available through this app but can be developed using a similar approach to server admin endpoint
''' The sample uses Raster API to populate dataset properties (used to construct service configuration), and can eitehr directly invoke rest Admin API to create service; or using AGSClient to create service.
''' 2. Case sensitivity:  
''' (1) switches are case sensitive. 
''' (2) when publish a service, the service name is case sensitive
''' 3. Usage:
''' Run from command line environment. Usage. <>: required parameter; |: pick one.
''' isconfig -o publish -h <host_adminurl> -d <datapath> -n <serviceName>
''' isconfig -o <delete|start|stop|pause> -h <host> -n <serviceName>
''' isconfig -o <list> -h <host>
''' Example 1: isconfig -o publish -h "http://host:6080/arcgis/admin" -u "adminuser" -p "adminpassword" -d \\myserver\data\test.gdb\mdtest -n mdtest
''' Example 2: isconfig -o stop -h myservername -u "adminuser" -p "adminpassword" -n mdtest
''' Example 3: isconfig -o list -h myservername -u "adminuser" -p "adminpassword"
''' </summary>
Class ISConfig
	#Region "static variables"
	Private Shared sourcePath As String = ""
	'data source path: a raster dataset, a mosaic dataset
	Private Shared restAdmin As String = ""
	'host admin url e.g. http://host:6080/arcgis/admin
	Private Shared serviceName As String = ""
	'image service name        
	Private Shared rasterDataset As IRasterDataset = Nothing
	Private Shared soAdmin As IServerObjectAdmin = Nothing
	Private Shared username As String = ""
	'user name for publisher/admin
	Private Shared password As String = ""
	'password for publisher/admin
	#End Region
	<STAThread> _
	Public Shared Sub Main(args As String())
		Try
            'args = {"-o", "publish", "-h", "http://server:6080/arcgis/admin", "-u", "adminuser", "-p", "adminpassword", "-d", "\\server\test\rgb.tif", "-n", "mdtest12356"}
            'args = {"-o", "list", "-h", "http://server:6080/arcgis/admin", "-u", "adminuser", "-p", "adminpassword"}
			'validation
			If Not ValidateParams(args) Then
				Return
			End If
			'license           
			If Not InitLicense() Then
				Return
			End If

			'retrieve parameters
			Retrieve_Params(args)
			Dim operation As String = args(1)
			Select Case operation.ToLower()
				Case "publish"
					'CreateISConfig();
					CreateISConfig_RESTAdmin()
					Exit Select
				Case "delete"
					'DeleteService();
					DeleteService_RESTAdmin()
					Exit Select
				Case "start"
					'StartService();
					StartService_RESTAdmin()
					Exit Select
				Case "stop"
					'StopService();
					StopService_RESTAdmin()
					Exit Select
				Case "pause"
					PauseService()
					Exit Select
				Case "list"
					'ListServices();
					ListServices_RESTAdmin()
					Exit Select
			End Select
		Catch exc As Exception
			Console.WriteLine("Error: {0}", exc.Message)
		End Try
	End Sub


	#Region "management operations"
	''' <summary>
	''' create image service configuration
	''' </summary>
	Private Shared Sub CreateISConfig()
		Try
			If Not ConnectAGS(restAdmin) Then
				Return
			End If

			'get source type
			Dim sourceType As esriImageServiceSourceType = GetSourceType(sourcePath)

			'connect to ArcGIS Server and create configuration
			Dim soConfig As IServerObjectConfiguration5 = DirectCast(soAdmin.CreateConfiguration(), IServerObjectConfiguration5)

			'set general service parameters
			soConfig.Name = serviceName
			soConfig.TypeName = "ImageServer"
			soConfig.TargetCluster = "default"

			soConfig.StartupType = esriStartupType.esriSTAutomatic
			soConfig.IsPooled = True
			soConfig.IsolationLevel = esriServerIsolationLevel.esriServerIsolationHigh
			soConfig.MinInstances = 1
			soConfig.MaxInstances = 2

			'customize recycle properties
			Dim propertySet_Recycle As IPropertySet = soConfig.RecycleProperties
			propertySet_Recycle.SetProperty("Interval", "24")


			'path to the data
			Dim propertySet As IPropertySet = soConfig.Properties
			Dim workspace As IWorkspace = DirectCast(rasterDataset, IDataset).Workspace
			If workspace.WorkspaceFactory.WorkspaceType = esriWorkspaceType.esriRemoteDatabaseWorkspace Then
				Dim wsName2 As IWorkspaceName2 = TryCast(DirectCast(workspace, IDataset).FullName, IWorkspaceName2)
				Dim connString As String = wsName2.ConnectionString
				propertySet.SetProperty("ConnectionString", connString)
				propertySet.SetProperty("Raster", DirectCast(rasterDataset, IDataset).Name)
			Else
				propertySet.SetProperty("Path", sourcePath)
			End If
			propertySet.SetProperty("EsriImageServiceSourceType", sourceType.ToString())

			'MIME+URL (virtual directory)
			propertySet.SetProperty("SupportedImageReturnTypes", "MIME+URL")
			Dim dirs As IEnumServerDirectory = soAdmin.GetServerDirectories()
			dirs.Reset()
			Dim serverDir As IServerDirectory = dirs.[Next]()
			While serverDir IsNot Nothing
				If DirectCast(serverDir, IServerDirectory2).Type = esriServerDirectoryType.esriSDTypeOutput Then
					propertySet.SetProperty("OutputDir", serverDir.Path)
					propertySet.SetProperty("VirtualOutputDir", serverDir.URL)
					Exit While
				End If
				serverDir = dirs.[Next]()
			End While

			'copy right
			propertySet.SetProperty("CopyRight", "")

			'properties for a mosaic dataset;
			If sourceType = esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset Then
				Dim functionRasterDataset As IFunctionRasterDataset = DirectCast(rasterDataset, IFunctionRasterDataset)
				Dim propDefaults As IPropertySet = functionRasterDataset.Properties

				Dim names As Object, values As Object
				propDefaults.GetAllProperties(names, values)
				Dim propNames As New List(Of String)()
				propNames.AddRange(DirectCast(names, String()))
				If propNames.Contains("MaxImageHeight") Then
					propertySet.SetProperty("MaxImageHeight", propDefaults.GetProperty("MaxImageHeight"))
				End If
				'4100
				If propNames.Contains("MaxImageWidth") Then
					propertySet.SetProperty("MaxImageWidth", propDefaults.GetProperty("MaxImageWidth"))
				End If
				'15000
				If propNames.Contains("AllowedCompressions") Then
					propertySet.SetProperty("AllowedCompressions", propDefaults.GetProperty("AllowedCompressions"))
				End If
				'"None,JPEG,LZ77,LERC"
				If propNames.Contains("DefaultResamplingMethod") Then
					propertySet.SetProperty("DefaultResamplingMethod", propDefaults.GetProperty("DefaultResamplingMethod"))
				End If
				'0
				If propNames.Contains("DefaultCompressionQuality") Then
					propertySet.SetProperty("DefaultCompressionQuality", propDefaults.GetProperty("DefaultCompressionQuality"))
				End If
				'75
				If propNames.Contains("MaxRecordCount") Then
					propertySet.SetProperty("MaxRecordCount", propDefaults.GetProperty("MaxRecordCount"))
				End If
				'500
				If propNames.Contains("MaxMosaicImageCount") Then
					propertySet.SetProperty("MaxMosaicImageCount", propDefaults.GetProperty("MaxMosaicImageCount"))
				End If
				'20
				If propNames.Contains("MaxDownloadSizeLimit") Then
					propertySet.SetProperty("MaxDownloadSizeLimit", propDefaults.GetProperty("MaxDownloadSizeLimit"))
				End If
				'20
				If propNames.Contains("MaxDownloadImageCount") Then
					propertySet.SetProperty("MaxDownloadImageCount", propDefaults.GetProperty("MaxDownloadImageCount"))
				End If
				'20
				If propNames.Contains("AllowedFields") Then
					propertySet.SetProperty("AllowedFields", propDefaults.GetProperty("AllowedFields"))
				End If
				'"Name,MinPS,MaxPS,LowPS,HighPS,CenterX,CenterY"
				If propNames.Contains("AllowedMosaicMethods") Then
					propertySet.SetProperty("AllowedMosaicMethods", propDefaults.GetProperty("AllowedMosaicMethods"))
				End If
				'"Center,NorthWest,LockRaster,ByAttribute,Nadir,Viewpoint,Seamline"
				If propNames.Contains("AllowedItemMetadata") Then
					propertySet.SetProperty("AllowedItemMetadata", propDefaults.GetProperty("AllowedItemMetadata"))
				End If
				'"Full"
				If propNames.Contains("AllowedMensurationCapabilities") Then
					propertySet.SetProperty("AllowedMensurationCapabilities", propDefaults.GetProperty("AllowedMensurationCapabilities"))
				End If
				'"Full"
				If propNames.Contains("DefaultCompressionTolerance") Then
					propertySet.SetProperty("DefaultCompressionTolerance", propDefaults.GetProperty("DefaultCompressionTolerance"))
					'"0.01" LERC compression
					'propertySet.SetProperty("RasterFunctions", @"\\server\dir\rft1.rft.xml,\\server\dir\rft2.rft.xml");//"put raster function templates here, the first one is applied to exportimage request by default"
					'propertySet.SetProperty("RasterTypes", @"Raster Dataset,\\server\dir\art1.art.xml,\\server\dir\art2.art");//"put raster types here"
					'propertySet.SetProperty("DynamicImageWorkspace", @"\\server\dynamicImageDir"); //put the workspace that holds uploaded imagery here
					'propertySet.SetProperty("supportsOwnershipBasedAccessControl", true); //ownership based access control
					'propertySet.SetProperty("AllowOthersToUpdate", true); //allow others to update a catalog item
					'propertySet.SetProperty("AllowOthersToDelete", true); //allow others to delete a catalog item
					'propertySet.SetProperty("DownloadDir", ""); //put the download directory here
					'propertySet.SetProperty("VirutalDownloadDir", ""); //put the virtual download directory here
				End If
			Else
				propertySet.SetProperty("MaxImageHeight", 4100)
				propertySet.SetProperty("MaxImageWidth", 15000)
				propertySet.SetProperty("AllowedCompressions", "None,JPEG,LZ77")
				propertySet.SetProperty("DefaultResamplingMethod", 0)
				propertySet.SetProperty("DefaultCompressionQuality", 75)
				'for jpg compression
				propertySet.SetProperty("DefaultCompressionTolerance", 0.01)
				'for LERC compression                 
				'    rasterDataset = OpenRasterDataset(sourcePath);
				Dim measure As IMensuration = New MensurationClass()
				measure.Raster = DirectCast(rasterDataset, IRasterDataset2).CreateFullRaster()
				Dim mensurationCaps As String = ""
				If measure.CanMeasure Then
					mensurationCaps = "Basic"
				End If
				If measure.CanMeasureHeightBaseToTop Then
					mensurationCaps += ",Base-Top Height"
				End If
				If measure.CanMeasureHeightBaseToTopShadow Then
					mensurationCaps += ",Base-Top Shadow Height"
				End If
				If measure.CanMeasureHeightTopToTopShadow Then
					mensurationCaps += ",Top-Top Shadow Height"
				End If
					'set mensuration here
				propertySet.SetProperty("AllowedMensurationCapabilities", mensurationCaps)
			End If

			'not cached
			propertySet.SetProperty("IsCached", False)
			propertySet.SetProperty("IgnoreCache", True)
			propertySet.SetProperty("UseLocalCacheDir", False)
			propertySet.SetProperty("ClientCachingAllowed", False)

			'propertySet.SetProperty("DEM", ""); //put the elevation raster dataset or service for 3D mensuration, may need to add 3D to AllowedMensurationCapabilities

			'convert colormap to RGB or not
			propertySet.SetProperty("ColormapToRGB", False)

			'whether to return jpgs for all jpgpng request or not
			propertySet.SetProperty("ReturnJPGPNGAsJPG", False)

			'allow server to process client defined function
			propertySet.SetProperty("AllowFunction", True)
			'allow raster function

			'capabilities
			If sourceType = esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset Then
				soConfig.Info.SetProperty("Capabilities", "Image,Catalog,Metadata,Mensuration")
			Else
				'Full set: Image,Catalog,Metadata,Download,Pixels,Edit,Mensuration
				soConfig.Info.SetProperty("Capabilities", "Image,Metadata,Mensuration")
			End If

			'enable wcs, assume data has spatial reference
			soConfig.set_ExtensionEnabled("WCSServer", True)
			Dim wcsInfo As IPropertySet = New PropertySetClass()
			wcsInfo.SetProperty("WebEnabled", "true")
			soConfig.set_ExtensionInfo("WCSServer", wcsInfo)
			Dim propertySetWCS As IPropertySet = New PropertySetClass()
			propertySetWCS.SetProperty("CustomGetCapabilities", False)
			propertySetWCS.SetProperty("PathToCustomGetCapabilitiesFiles", "")
			soConfig.set_ExtensionProperties("WCSServer", propertySetWCS)

			'enable wms
			soConfig.set_ExtensionEnabled("WMSServer", True)
			Dim wmsInfo As IPropertySet = New PropertySetClass()
			wmsInfo.SetProperty("WebEnabled", "true")
			soConfig.set_ExtensionInfo("WMSServer", wmsInfo)
			Dim propertySetWMS As IPropertySet = New PropertySetClass()
			propertySetWMS.SetProperty("name", "WMS")
			'set other properties here
			soConfig.set_ExtensionProperties("WMSServer", propertySetWMS)


			'add configuration and start
			soAdmin.AddConfiguration(soConfig)
			soAdmin.StartConfiguration(serviceName, "ImageServer")

			If soAdmin.GetConfigurationStatus(serviceName, "ImageServer").Status = esriConfigurationStatus.esriCSStarted Then
				Console.WriteLine("{0} on {1} has been configured and started.", serviceName, restAdmin)
			Else
				Console.WriteLine("{0} on {1} was configured but can not be started, please investigate.", serviceName, restAdmin)
			End If

			If rasterDataset IsNot Nothing Then
				System.Runtime.InteropServices.Marshal.ReleaseComObject(rasterDataset)
			End If
		Catch exc As Exception
			Console.WriteLine("Error: {0}", exc.Message)
		End Try
	End Sub

	''' <summary>
	''' delete a service
	''' </summary>
	Private Shared Sub DeleteService()
		Try
			If Not ConnectAGS(restAdmin) Then
				Return
			End If
			If Not ValidateServiceName(soAdmin, serviceName, restAdmin) Then
				Return
			End If
			soAdmin.DeleteConfiguration(serviceName, "ImageServer")
			Console.WriteLine("{0} on {1} was deleted successfully.", serviceName, restAdmin)
		Catch exc As Exception
			Console.WriteLine("Error: {0}", exc.Message)
		End Try
	End Sub

	''' <summary>
	''' start a service
	''' </summary>
	Private Shared Sub StartService()
		Try
			If Not ConnectAGS(restAdmin) Then
				Return
			End If
			If Not ValidateServiceName(soAdmin, serviceName, restAdmin) Then
				Return
			End If
			soAdmin.StartConfiguration(serviceName, "ImageServer")
			If soAdmin.GetConfigurationStatus(serviceName, "ImageServer").Status = esriConfigurationStatus.esriCSStarted Then
				Console.WriteLine("{0} on {1} was started successfully.", serviceName, restAdmin)
			Else
				Console.WriteLine("{0} on {1} couldn't be started, please investigate.", serviceName, restAdmin)
			End If
		Catch exc As Exception
			Console.WriteLine("Error: {0}", exc.Message)
		End Try
	End Sub

	''' <summary>
	''' stop a service
	''' </summary>
	Private Shared Sub StopService()
		Try
			If Not ConnectAGS(restAdmin) Then
				Return
			End If
			If Not ValidateServiceName(soAdmin, serviceName, restAdmin) Then
				Return
			End If
			soAdmin.StopConfiguration(serviceName, "ImageServer")
			If soAdmin.GetConfigurationStatus(serviceName, "ImageServer").Status = esriConfigurationStatus.esriCSStopped Then
				Console.WriteLine("{0} on {1} was stopped successfully.", serviceName, restAdmin)
			Else
				Console.WriteLine("{0} on {1} couldn't be stopped, please investigate.", serviceName, restAdmin)
			End If
		Catch exc As Exception
			Console.WriteLine("Error: {0}", exc.Message)
		End Try
	End Sub

	''' <summary>
	''' pause a service
	''' </summary>
	Private Shared Sub PauseService()
		Try
			If Not ConnectAGS(restAdmin) Then
				Return
			End If
			If Not ValidateServiceName(soAdmin, serviceName, restAdmin) Then
				Return
			End If
			If (soAdmin.GetConfigurationStatus(serviceName, "ImageServer").Status = esriConfigurationStatus.esriCSStopped) Then
				Console.WriteLine("{0} on {1} is currently stopped --- not paused.", serviceName, restAdmin)
				Return
			End If
			soAdmin.PauseConfiguration(serviceName, "ImageServer")
			If soAdmin.GetConfigurationStatus(serviceName, "ImageServer").Status = esriConfigurationStatus.esriCSPaused Then
				Console.WriteLine("{0} on {1} was paused successfully.", serviceName, restAdmin)
			Else
				Console.WriteLine("{0} on {1} couldn't be paused, please investigate.", serviceName, restAdmin)
			End If
		Catch exc As Exception
			Console.WriteLine("Error: {0}", exc.Message)
		End Try
	End Sub

	''' <summary>
	''' List services
	''' </summary>
	Private Shared Sub ListServices()
		Try
			If Not ConnectAGS(restAdmin) Then
				Return
			End If
			Dim enumConfigs As IEnumServerObjectConfiguration = soAdmin.GetConfigurations()
			enumConfigs.Reset()
			Dim soConfig As IServerObjectConfiguration = enumConfigs.[Next]()
			Console.WriteLine("ArcGIS Server {0} has the following image services:", restAdmin)
			While soConfig IsNot Nothing
				If soConfig.TypeName = "ImageServer" Then
					Console.WriteLine("{0}", soConfig.Name)
				End If
				soConfig = enumConfigs.[Next]()
			End While
		Catch exc As Exception
			Console.WriteLine("Error: {0}", exc.Message)
		End Try
	End Sub
	#End Region


	#Region "validation etc."
	''' <summary>
	''' connect to ags server
	''' </summary>
	''' <param name="host">host</param>
	''' <returns>true if connected</returns>
	Private Shared Function ConnectAGS(host As String) As Boolean
		Try
			Dim propertySet As IPropertySet = New PropertySetClass()
			propertySet.SetProperty("url", host)
			propertySet.SetProperty("ConnectionMode", esriAGSConnectionMode.esriAGSConnectionModePublisher)
			propertySet.SetProperty("ServerType", esriAGSServerType.esriAGSServerTypeDiscovery)
			propertySet.SetProperty("user", username)
			propertySet.SetProperty("password", password)
			propertySet.SetProperty("ALLOWINSECURETOKENURL", True)

			Dim connectName As IAGSServerConnectionName3 = TryCast(New AGSServerConnectionNameClass(), IAGSServerConnectionName3)
			connectName.ConnectionProperties = propertySet

			Dim agsAdmin As IAGSServerConnectionAdmin = TryCast(DirectCast(connectName, IName).Open(), IAGSServerConnectionAdmin)
			soAdmin = agsAdmin.ServerObjectAdmin
			Return True
		Catch exc As Exception
			Console.WriteLine("Error: Couldn't connect to AGSServer: {0}. Message: {1}", host, exc.Message)
			Return False
		End Try
	End Function

	''' <summary>
	''' Validate ServiceName
	''' </summary>
	''' <returns>Convert the config name to the correct case and returns true; if not exist in any cases, returns false </returns>
	Private Shared Function ValidateServiceName(soAdmin As IServerObjectAdmin, ByRef serviceName As String, host As String) As Boolean
		Dim enumConfigs As IEnumServerObjectConfiguration = soAdmin.GetConfigurations()
		enumConfigs.Reset()
		Dim soConfig As IServerObjectConfiguration = enumConfigs.[Next]()
		While soConfig IsNot Nothing
			If soConfig.Name.ToUpper() = serviceName.ToUpper() Then
				serviceName = soConfig.Name
				Return True
			End If
			soConfig = enumConfigs.[Next]()
		End While
		Console.WriteLine("Configuration {0} on {1} can not be found.", serviceName, host)
		Return False
	End Function

	''' <summary>
	''' Validate input parameters
	''' </summary>
	''' <param name="args">args</param>
	''' <returns>validation result</returns>
	Private Shared Function ValidateParams(args As String()) As Boolean
		'at least two params
		If args.Length = 0 Then
			ShowUsage()
			Console.WriteLine("press any key to continue ...")
			Console.ReadKey()
			Return False
		ElseIf args.Length < 2 Then
			' at least -o action
			ShowUsage()
			Return False
		End If

		' must start with -o
		Dim operations As String() = New String() {"publish", "delete", "start", "stop", "pause", "list"}
		If (Not args(0).StartsWith("-o")) OrElse (Not strInArray(args(1).ToLower(), operations)) Then
			Console.WriteLine("Incorrect operation")
			ShowUsage()
			Return False
		End If

		' for stop/start/pause/list, must contains "-n" and argument length is 4
		If (args(1).ToLower() = "stop") OrElse (args(1).ToLower() = "start") OrElse (args(1).ToLower() = "pause") OrElse (args(1).ToLower() = "delete") Then
			If Not strInArray("-h", args) Then
				Console.WriteLine("Missing host server -h")
				Return False
			End If
			If Not strInArray("-n", args) Then
				Console.WriteLine("Missing service name switch -n")
				Return False
			End If
			If Not strInArray("-u", args) Then
				Console.WriteLine("Missing admin/publisher username switch -u")
				Return False
			End If
			If Not strInArray("-p", args) Then
				Console.WriteLine("Missing admin/publisher name switch -p")
				Return False
				'if (args.Length > 8)
				'{
				'    Console.WriteLine("Too many arguments");
				'    return false;
				'}
			End If
		End If
		' for publish, must contains "-d" "-n" and argument length is 6
		If args(1).ToLower() = "publish" Then
			If Not strInArray("-d", args) Then
				Console.WriteLine("Missing data source switch -d")
				Return False
			End If
			If Not strInArray("-n", args) Then
				Console.WriteLine("Missing service name switch -n")
				Return False
			End If
			If Not strInArray("-u", args) Then
				Console.WriteLine("Missing admin/publisher username switch -u")
				Return False
			End If
			If Not strInArray("-p", args) Then
				Console.WriteLine("Missing admin/publisher name switch -p")
				Return False
				'if (args.Length > 12)
				'{
				'    Console.WriteLine("Too many arguments");
				'    return false;
				'}
			End If
		End If
		' validate each parameter: host, sourcepath, configname
		Dim parameters As String() = New String() {"-h", "-d", "-n", "-u", "-p"}
		For i As Integer = 2 To args.Length - 1
			Select Case args(i)
				Case "-h"
					If i = args.Length - 1 Then
						Console.WriteLine("Missing host parameter, switch -h")
						Return False
					ElseIf strInArray(args(i + 1), parameters) Then
						Console.WriteLine("Missing host parameter, switch -h")
						Return False
					End If
					i += 1
					Exit Select
				Case "-d"
					If i = args.Length - 1 Then
						Console.WriteLine("Missing data source parameter, switch -d")
						Return False
					ElseIf strInArray(args(i + 1), parameters) Then
						Console.WriteLine("Missing data source parameter, switch -d")
						Return False
					End If
					i += 1
					Exit Select
				Case "-n"
					If i = args.Length - 1 Then
						Console.WriteLine("Missing service name parameter, switch -n")
						Return False
					ElseIf strInArray(args(i + 1), parameters) Then
						Console.WriteLine("Missing service name parameter, switch -n")
						Return False
					End If
					i += 1
					Exit Select
				Case "-u"
					If i = args.Length - 1 Then
						Console.WriteLine("Missing admin/publisher username parameter, switch -u")
						Return False
					ElseIf strInArray(args(i + 1), parameters) Then
						Console.WriteLine("Missing admin/publisher username parameter, switch -u")
						Return False
					End If
					i += 1
					Exit Select
				Case "-p"
					If i = args.Length - 1 Then
						Console.WriteLine("Missing admin/publisher password parameter, switch -p")
						Return False
					ElseIf strInArray(args(i + 1), parameters) Then
						Console.WriteLine("Missing admin/publisher password parameter, switch -p")
						Return False
					End If
					i += 1
					Exit Select
				Case Else
					Console.WriteLine("Incorrect parameter switch: {0} is not a recognized.", args(i))
					Return False
			End Select
		Next
		Return True
	End Function

	''' <summary>
	''' string in array
	''' </summary>
	''' <param name="name"></param>
	''' <param name="nameArray"></param>
	''' <returns></returns>
	Private Shared Function strInArray(name As String, nameArray As String()) As Boolean
		For i As Integer = 0 To nameArray.Length - 1
			If nameArray(i) = name Then
				Return True
			End If
		Next
		Return False
	End Function

	''' <summary>
	''' initialize license
	''' </summary>
	''' <returns>status</returns>
	Private Shared Function InitLicense() As Boolean
		RuntimeManager.Bind(ProductCode.Desktop)
		Dim aoInit As IAoInitialize = New AoInitializeClass()
		Dim status As esriLicenseStatus = aoInit.Initialize(esriLicenseProductCode.esriLicenseProductCodeBasic)
		If status <> esriLicenseStatus.esriLicenseCheckedOut Then
			Console.WriteLine("License initialization error")
			Return False
		Else
			Return True
		End If
	End Function
	#End Region


	#Region "helper methods"
	''' <summary>
	''' Retrieve parameters
	''' </summary>
	''' <param name="args">args</param>
	Private Shared Sub Retrieve_Params(args As String())
		For i As Integer = 2 To args.Length - 1
			Select Case args(i)
				Case "-h"
					restAdmin = args(System.Threading.Interlocked.Increment(i))
					Exit Select
				Case "-d"
					sourcePath = args(System.Threading.Interlocked.Increment(i))
					Exit Select
				Case "-n"
					serviceName = args(System.Threading.Interlocked.Increment(i))
					Exit Select
				Case "-u"
					username = args(System.Threading.Interlocked.Increment(i))
					Exit Select
				Case "-p"
					password = args(System.Threading.Interlocked.Increment(i))
					Exit Select
			End Select
		Next
	End Sub

	''' <summary>
	''' Get Source Type
	''' </summary>
	''' <param name="sourcePath">path of the data source</param>
	''' <returns>data source type</returns>
	Private Shared Function GetSourceType(sourcePath As String) As esriImageServiceSourceType
		If sourcePath.ToLower().EndsWith(".lyr") Then
			Return esriImageServiceSourceType.esriImageServiceSourceTypeLayer
		Else
			Dim fileInfo As New FileInfo(sourcePath)
			OpenRasterDataset(fileInfo.DirectoryName, fileInfo.Name)
			If TypeOf rasterDataset Is IMosaicDataset Then
				Return esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset
			Else
				Return esriImageServiceSourceType.esriImageServiceSourceTypeDataset
			End If
		End If
	End Function

	''' <summary>
	''' Open Raster Dataset
	''' </summary>
	''' <param name="path">path of the dataset</param>
	''' <param name="rasterDSName">name of the dataset</param>        
	Private Shared Sub OpenRasterDataset(path As [String], rasterDSName As [String])
		'this is why the utility user needs access to data source. image service configurations varies among data sources.
		Dim workspaceFactory As IWorkspaceFactory = Nothing
		Dim workspace As IWorkspace = Nothing
		Dim rasterWorkspaceEx As IRasterWorkspaceEx = Nothing
		Dim factoryType As Type = Nothing
		Try
			Select Case path.Substring(path.Length - 4, 4).ToLower()
				' a path can never be shorter than 4 characters, isn't it? c:\a
				Case ".gdb"
					factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory")
					workspaceFactory = TryCast(Activator.CreateInstance(factoryType), IWorkspaceFactory)
					workspace = workspaceFactory.OpenFromFile(path, 1)
					rasterWorkspaceEx = DirectCast(workspace, IRasterWorkspaceEx)
					rasterDataset = rasterWorkspaceEx.OpenRasterDataset(rasterDSName)
					Exit Select
				Case ".sde"
					factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.SdeWorkspaceFactory")
					workspaceFactory = TryCast(Activator.CreateInstance(factoryType), IWorkspaceFactory)
					workspace = workspaceFactory.OpenFromFile(path, 1)
					rasterWorkspaceEx = DirectCast(workspace, IRasterWorkspaceEx)
					rasterDataset = rasterWorkspaceEx.OpenRasterDataset(rasterDSName)
					Exit Select
				Case Else
					factoryType = Type.GetTypeFromProgID("esriDataSourcesRaster.RasterWorkspaceFactory")
					workspaceFactory = TryCast(Activator.CreateInstance(factoryType), IWorkspaceFactory)
					workspace = workspaceFactory.OpenFromFile(path, 1)
					Dim rasterWorkspace As IRasterWorkspace = DirectCast(workspace, IRasterWorkspace)
					rasterDataset = rasterWorkspace.OpenRasterDataset(rasterDSName)
					Exit Select
			End Select
		Catch generatedExceptionName As Exception
			Throw New ArgumentException("Failed to open source data")
		End Try
	End Sub

	''' <summary>
	''' Show usage
	''' </summary>
	Private Shared Sub ShowUsage()
		Console.WriteLine()
		Console.WriteLine("ArcObject Sample: command line image service publishing and configuration utility (10.1 ArcGIS Server). Data is not copied to server using this tool. source data must be accessible by ArcGIS Server running account. CachingScheme can't be defined through this tool but can be done through Caching geoprocessing tools. REST Metadata/thumbnail/iteminfo resource are not available through this app but can be developed using a similar approach to server admin endpoint.")
		Console.WriteLine()
		Console.WriteLine("Usage. <>: required parameter; |: pick one.")
		Console.WriteLine("isconfig -o publish -h <host_admin_url> -u <adminuser> -p <adminpassword> -d <datapath> -n <serviceName>")
		Console.WriteLine("isconfig -o <delete|start|stop> -h <host_admin_url> -u <adminuser> -p <adminpassword> -n <serviceName>")
		Console.WriteLine("isconfig -o <list> -h <host_admin_url> -u <adminuser> -p <adminpassword>")
		Console.WriteLine("e.g. isconfig -o list -h http://myserver:6080/arcgis/admin -u username -p password")
	End Sub
	#End Region

	#Region "REST Admin based http requests"
	''' <summary>
	''' Generate a token
	''' </summary>
	''' <param name="restAdmin">REST admin url: http://server:port/arcigs/admin</param>
	''' <returns>A token that has default expiration time</returns>
	Public Shared Function GenerateAGSToken_RESTAdmin() As String
		Try
			Dim loginUrl As String = restAdmin & "/generateToken"
			Dim request As WebRequest = WebRequest.Create(loginUrl)
			request.Method = "POST"
			Dim credential As String = "username=" & username & "&password=" & password & "&client=requestip&expiration=&f=json"
			Dim content As Byte() = Encoding.UTF8.GetBytes(credential)
			request.ContentLength = content.Length
			request.ContentType = "application/x-www-form-urlencoded"
			Dim requestStream As Stream = request.GetRequestStream()
			requestStream.Write(content, 0, content.Length)
			requestStream.Close()
			Dim response As WebResponse = request.GetResponse()
			Dim responseStream As Stream = response.GetResponseStream()
			Dim reader As New StreamReader(responseStream)
			Dim result As String = reader.ReadToEnd()
			Dim index1 As Integer = result.IndexOf("token"":""") + "token"":""".Length
			Dim index2 As Integer = result.IndexOf("""", index1)
			'Dictionary<string, object> dictResult = DeserializeJSON(result, true);
			Dim token As String = result.Substring(index1, index2 - index1)
			Return token
		Catch
			Return ""
		End Try
	End Function

	''' <summary>
	''' Create arcgis server folder
	''' </summary>
	''' <param name="restAdmin">REST admin url, e.g. http://server:port/arcgis/admin</param>
	''' <param name="folderName">Folder name</param>
	''' <param name="description">Description of the folder</param>
	''' <returns>True if successfully created</returns>
	Private Shared Function CreateServerFolder_RESTAdmin(folderName As String, description As String) As Boolean
		Try
			Dim token As String = GenerateAGSToken_RESTAdmin()
			restAdmin = If(restAdmin.EndsWith("/"), restAdmin.Substring(0, restAdmin.Length - 1), restAdmin)
			Dim folderUrl As String = restAdmin & "/services/" & folderName & "?f=json&token=" & token
			Dim request As WebRequest = WebRequest.Create(folderUrl)
			Dim response As WebResponse = request.GetResponse()
			Dim responseStream As Stream = response.GetResponseStream()
			Dim reader As New StreamReader(responseStream)
			Dim result As String = reader.ReadToEnd()
			If Not result.Contains("error") Then
				Return True
			Else
				Dim createFolderUrl As String = restAdmin & "/services/createFolder"
				request = WebRequest.Create(createFolderUrl)
				Dim postcontent As String = String.Format("folderName={0}&description={1}&f=pjson&token={2}", folderName, description, token)
				Dim content As [Byte]() = Encoding.UTF8.GetBytes(postcontent)
				request.ContentLength = content.Length
				'((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
				request.ContentType = "application/x-www-form-urlencoded"
				request.Method = "POST"
				Dim requestStream As Stream = request.GetRequestStream()
				requestStream.Write(content, 0, content.Length)
				requestStream.Close()
				response = request.GetResponse()
				responseStream = response.GetResponseStream()
				reader = New StreamReader(responseStream)
				result = reader.ReadToEnd()
				Return result.Contains("success")
			End If
		Catch
			Return False
		End Try
	End Function
	Private Shared Sub GetServerDirectory_RESTAdmin(dirType As String, ByRef physicalPath As String, ByRef virtualPath As String)
		physicalPath = ""
		virtualPath = ""
		Try
			Dim token As String = GenerateAGSToken_RESTAdmin()
			restAdmin = If(restAdmin.EndsWith("/"), restAdmin.Substring(0, restAdmin.Length - 1), restAdmin)
			Dim directoryAlias As String = dirType.ToString().ToLower().Replace("esrisdtype", "arcgis")
			Dim directoryUrl As String = restAdmin & "/system/directories/" & directoryAlias & "?f=json&token=" & token
			Dim request As WebRequest = WebRequest.Create(directoryUrl)
			Dim response As WebResponse = request.GetResponse()
			Dim responseStream As Stream = response.GetResponseStream()
			Dim reader As New StreamReader(responseStream)
			Dim result As String = reader.ReadToEnd()
			Try
				Dim index As Integer = result.IndexOf(dirType)
				Dim index1 As Integer = result.IndexOf("physicalPath"":""", index) + "physicalPath"":""".Length
				Dim index2 As Integer = result.IndexOf("""", index1)
				physicalPath = result.Substring(index1, index2 - index1)

				index1 = result.IndexOf("virtualPath"":""", index) + "virtualPath"":""".Length
				index2 = result.IndexOf("""", index1)
				virtualPath = result.Substring(index1, index2 - index1)
			Catch
			End Try
		Catch
		End Try
	End Sub
	''' <summary>
	''' Delete Service
	''' </summary>
	''' <param name="restAdmin">REST admin url, e.g. http://server:port/arcgis/admin</param>
	''' <param name="serviceName">Service Name</param>
	''' <param name="serviceType">Server Type, e.g. ImageServer, MapServer, GeoDataServer, GeoprocessingServer, GeometryServer, etc</param>
	''' <returns>True if successfully deleted</returns>
	Public Shared Function DeleteService_RESTAdmin() As Boolean
		Try
			Dim token As String = GenerateAGSToken_RESTAdmin()
			restAdmin = If(restAdmin.EndsWith("/"), restAdmin.Substring(0, restAdmin.Length - 1), restAdmin)
			Dim serviceUrl As String = restAdmin & "/services/" & serviceName & "." & "ImageServer" & "/delete"
			Dim request As WebRequest = WebRequest.Create(serviceUrl)
			Dim postcontent As String = "f=pjson&token=" & token
			Dim content As [Byte]() = Encoding.UTF8.GetBytes(postcontent)
			request.ContentLength = content.Length
			'((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
			request.ContentType = "application/x-www-form-urlencoded"
			request.Method = "POST"
			Dim requestStream As Stream = request.GetRequestStream()
			requestStream.Write(content, 0, content.Length)
			requestStream.Close()
			Dim response As WebResponse = request.GetResponse()
			Dim responseStream As Stream = response.GetResponseStream()
			Dim reader As New StreamReader(responseStream)
			Dim result As String = reader.ReadToEnd()
			Console.WriteLine("delete service {0}, result: {1}", serviceName, result)
			Return result.Contains("success")
		Catch
			Return False
		End Try
	End Function

	Public Shared Function StartService_RESTAdmin() As Boolean
		Try
			Dim token As String = GenerateAGSToken_RESTAdmin()
			restAdmin = If(restAdmin.EndsWith("/"), restAdmin.Substring(0, restAdmin.Length - 1), restAdmin)
			Dim serviceUrl As String = restAdmin & "/services/" & serviceName & "." & "ImageServer" & "/start"
			Dim request As WebRequest = WebRequest.Create(serviceUrl)
			Dim postcontent As String = "f=pjson&token=" & token
			Dim content As [Byte]() = Encoding.UTF8.GetBytes(postcontent)
			request.ContentLength = content.Length
			'((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
			request.ContentType = "application/x-www-form-urlencoded"
			request.Method = "POST"
			Dim requestStream As Stream = request.GetRequestStream()
			requestStream.Write(content, 0, content.Length)
			requestStream.Close()
			Dim response As WebResponse = request.GetResponse()
			Dim responseStream As Stream = response.GetResponseStream()
			Dim reader As New StreamReader(responseStream)
			Dim result As String = reader.ReadToEnd()
			Console.WriteLine("start service {0}, result: {1}", serviceName, result)
			Return result.Contains("success")
		Catch
			Return False
		End Try
	End Function

	Public Shared Function StopService_RESTAdmin() As Boolean
		Try
			Dim token As String = GenerateAGSToken_RESTAdmin()
			restAdmin = If(restAdmin.EndsWith("/"), restAdmin.Substring(0, restAdmin.Length - 1), restAdmin)
			Dim serviceUrl As String = restAdmin & "/services/" & serviceName & "." & "ImageServer" & "/stop"
			Dim request As WebRequest = WebRequest.Create(serviceUrl)
			Dim postcontent As String = "f=pjson&token=" & token
			Dim content As [Byte]() = Encoding.UTF8.GetBytes(postcontent)
			request.ContentLength = content.Length
			'((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
			request.ContentType = "application/x-www-form-urlencoded"
			request.Method = "POST"
			Dim requestStream As Stream = request.GetRequestStream()
			requestStream.Write(content, 0, content.Length)
			requestStream.Close()
			Dim response As WebResponse = request.GetResponse()
			Dim responseStream As Stream = response.GetResponseStream()
			Dim reader As New StreamReader(responseStream)
			Dim result As String = reader.ReadToEnd()
			Console.WriteLine("stop service {0}, result: {1}", serviceName, result)
			Return result.Contains("success")
		Catch
			Return False
		End Try
	End Function
	Public Shared Sub ListServices_RESTAdmin()
		Console.WriteLine("List of image services: ")
		ListServices_RESTAdmin(restAdmin & "/services", "")
	End Sub
	Public Shared Sub ListServices_RESTAdmin(root As String, folder As String)
		Try
			Dim token As String = GenerateAGSToken_RESTAdmin()
			restAdmin = If(restAdmin.EndsWith("/"), restAdmin.Substring(0, restAdmin.Length - 1), restAdmin)
			Dim serviceUrl As String = root & "/" & folder
			Dim request As WebRequest = WebRequest.Create(serviceUrl)
			Dim postcontent As String = "f=json&token=" & token
			Dim content As [Byte]() = Encoding.UTF8.GetBytes(postcontent)
			request.ContentLength = content.Length
			'((HttpWebRequest)request).UserAgent = "Mozilla/4.0";
			request.ContentType = "application/x-www-form-urlencoded"
			request.Method = "POST"
			Dim requestStream As Stream = request.GetRequestStream()
			requestStream.Write(content, 0, content.Length)
			requestStream.Close()
			Dim response As WebResponse = request.GetResponse()
			Dim responseStream As Stream = response.GetResponseStream()
			Dim reader As New StreamReader(responseStream)
			Dim result As String = reader.ReadToEnd()
			Dim indexfolder1 As Integer = result.IndexOf("folders"":[")
			If indexfolder1 <> -1 Then
				indexfolder1 += "folders"":[".Length
				Dim indexfolder2 As Integer = result.IndexOf("]", indexfolder1)
				Dim folderlist As String = result.Substring(indexfolder1, indexfolder2 - indexfolder1)
				Dim folders As String() = folderlist.Replace("""", "").Split(","C)
				For Each subfolder As String In folders
					ListServices_RESTAdmin(serviceUrl, subfolder)
				Next
			End If


			Dim index As Integer = result.IndexOf("services")
			While index > 0
				Try
					Dim index1 As Integer = result.IndexOf("folderName"":""", index)
                    If index1 = -1 Then
                        Exit While
                    End If
					index1 += "folderName"":""".Length
					Dim index2 As Integer = result.IndexOf("""", index1)
					Dim folderName As String = result.Substring(index1, index2 - index1)

					index1 = result.IndexOf("serviceName"":""", index2) + "serviceName"":""".Length
					index2 = result.IndexOf("""", index1)
					Dim serviceName As String = result.Substring(index1, index2 - index1)

					index1 = result.IndexOf("type"":""", index2) + "type"":""".Length
					index2 = result.IndexOf("""", index1)
					Dim serviceType As String = result.Substring(index1, index2 - index1)
					If serviceType = "ImageServer" Then
						If folderName = "/" Then
							'root
							Console.WriteLine(serviceName)
						Else
							Console.WriteLine(folderName & "/" & serviceName)
						End If
					End If
					index = index2
				Catch
				End Try
			End While
		Catch
		End Try
	End Sub
	''' <summary>
	''' create image service
	''' </summary>
	''' <param name="restAdmin">host machine name (windows or linux)</param>
	''' <param name="sourcePath">data source path, must be windows path (linux path is constructed automaticlly by windows path)</param>
	''' <param name="serviceName">configuration name</param>
	''' <param name="createImageServiceParams">Cration parameters, e.g. raster functions, colormaptorgb, raster types, dem, dynamicimageworkspace, customized propertyset etc</param>
	''' <returns>true if created successfully</returns>
	Public Shared Function CreateISConfig_RESTAdmin() As Boolean
		'string restAdmin, string username, string password, string sourcePath, string serviceName
		Try
			Dim sourceType As esriImageServiceSourceType = GetSourceType(sourcePath)

			Dim serviceType As String = "ImageServer"
			'DeleteService_RESTAdmin();
			restAdmin = If(restAdmin.EndsWith("/"), restAdmin.Substring(0, restAdmin.Length - 1), restAdmin)
			Dim serviceFolder As String = ""
			If serviceName.Contains("/") Then
				serviceFolder = serviceName.Substring(0, serviceName.IndexOf("/"))
				CreateServerFolder_RESTAdmin(serviceFolder, "")
				serviceName = serviceName.Substring(serviceFolder.Length + 1, serviceName.Length - serviceFolder.Length - 1)
			End If
			Dim createServiceUrl As String = ""
			If serviceFolder = "" Then
				createServiceUrl = restAdmin & "/services/createService"
			Else
				createServiceUrl = restAdmin & "/services/" & serviceFolder & "/createService"
			End If
			'createServiceUrl = "http://wenxue:6080/arcgis/admin/services/createService";
			Dim request As WebRequest = WebRequest.Create(createServiceUrl)

			'DataSourceIsReadOnly                                                                                                                                                                                                                                                                                                                                                                                                            
			Dim sBuilder As New StringBuilder()
			sBuilder.Append("{")
			sBuilder.AppendFormat("{0}: {1},", QuoteString("serviceName"), QuoteString(serviceName))
			sBuilder.AppendFormat("{0}: {1},", QuoteString("type"), QuoteString(serviceType))
			sBuilder.AppendFormat("{0}: {1},", QuoteString("description"), QuoteString(""))

			sBuilder.AppendFormat("{0}: {1},", QuoteString("clusterName"), QuoteString("default"))
			sBuilder.AppendFormat("{0}: {1},", QuoteString("minInstancesPerNode"), 1)
			sBuilder.AppendFormat("{0}: {1},", QuoteString("maxInstancesPerNode"), 2)
			sBuilder.AppendFormat("{0}: {1},", QuoteString("maxWaitTime"), 10000)
			sBuilder.AppendFormat("{0}: {1},", QuoteString("maxIdleTime"), 1800)
			sBuilder.AppendFormat("{0}: {1},", QuoteString("maxUsageTime"), 600)
			sBuilder.AppendFormat("{0}: {1},", QuoteString("loadBalancing"), QuoteString("ROUND_ROBIN"))
			sBuilder.AppendFormat("{0}: {1},", QuoteString("isolationLevel"), QuoteString("HIGH"))
			sBuilder.AppendFormat("{0}: {1},", QuoteString("configuredState"), QuoteString("STARTED"))

			Dim webCapabilities As String = ""

			If sourceType = esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset Then
				webCapabilities = "Image,Catalog,Metadata,Mensuration"
			Else
				'full list "Image,Catalog,Metadata,Download,Pixels,Edit,Mensuration"
				webCapabilities = "Image,Metadata,Mensuration"
			End If
			sBuilder.AppendFormat("{0}: {1},", QuoteString("capabilities"), QuoteString(webCapabilities))


			sBuilder.AppendFormat("{0}: {1}", QuoteString("properties"), "{")
			sBuilder.AppendFormat("{0}: {1},", QuoteString("supportedImageReturnTypes"), QuoteString("MIME+URL"))

			Dim workspace As IWorkspace = DirectCast(rasterDataset, IDataset).Workspace
			If workspace.WorkspaceFactory.WorkspaceType = esriWorkspaceType.esriRemoteDatabaseWorkspace Then
				Dim wsName2 As IWorkspaceName2 = TryCast(DirectCast(workspace, IDataset).FullName, IWorkspaceName2)
				Dim connString As String = wsName2.ConnectionString
				sBuilder.AppendFormat("{0}: {1},", QuoteString("connectionString"), QuoteString(connString))
				sBuilder.AppendFormat("{0}: {1},", QuoteString("raster"), QuoteString(DirectCast(rasterDataset, IDataset).Name))
			Else
				sBuilder.AppendFormat("{0}: {1},", QuoteString("path"), QuoteString(sourcePath.Replace("\", "\\")))
			End If

			sBuilder.AppendFormat("{0}: {1},", QuoteString("esriImageServiceSourceType"), QuoteString(sourceType.ToString()))

			Dim outputDir As String = ""
			Dim virtualDir As String = ""

			GetServerDirectory_RESTAdmin("arcgisoutput", outputDir, virtualDir)

			Dim cacheDir As String = ""
			Dim virtualCacheDir As String = ""
			GetServerDirectory_RESTAdmin("arcgisoutput", cacheDir, virtualCacheDir)


			If outputDir <> "" Then
				sBuilder.AppendFormat("{0}: {1},", QuoteString("outputDir"), QuoteString(outputDir))
					'http://istest2:6080/arcgis/server/arcgisoutput"));
					'sBuilder.AppendFormat("{0}: {1},", QuoteString("dynamicImageWorkspace"), QuoteString(@"D:\UploadDir"));                    
				sBuilder.AppendFormat("{0}: {1},", QuoteString("virtualOutputDir"), QuoteString(virtualDir))
			End If
			'if (cacheDir != "")
			'{
			'    sBuilder.AppendFormat("{0}: {1},", QuoteString("cacheDir"), QuoteString(cacheDir));
			'    sBuilder.AppendFormat("{0}: {1},", QuoteString("virtualCacheDir"), QuoteString(virtualCacheDir));//http://istest2:6080/arcgis/server/arcgisoutput"));                    
			'}
			sBuilder.AppendFormat("{0}: {1},", QuoteString("copyright"), QuoteString(""))

			'properties for a mosaic Dataset;
			If sourceType = esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset Then
				Dim functionRasterDataset As IFunctionRasterDataset = DirectCast(rasterDataset, IFunctionRasterDataset)
				Dim propDefaults As IPropertySet = functionRasterDataset.Properties
				Dim names As Object, values As Object
				propDefaults.GetAllProperties(names, values)
				Dim propNames As New List(Of String)()
				propNames.AddRange(DirectCast(names, String()))
				If propNames.Contains("AllowedCompressions") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedCompressions"), QuoteString(propDefaults.GetProperty("AllowedCompressions").ToString()))
				End If
				'string
				If propNames.Contains("MaxImageHeight") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("maxImageHeight"), QuoteString(propDefaults.GetProperty("MaxImageHeight").ToString()))
				End If
				'should be int     
				If propNames.Contains("MaxImageWidth") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("maxImageWidth"), QuoteString(propDefaults.GetProperty("MaxImageWidth").ToString()))
				End If
				'should be int
				If propNames.Contains("DefaultResamplingMethod") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultResamplingMethod"), QuoteString(propDefaults.GetProperty("DefaultResamplingMethod").ToString()))
				End If
				'should be int
				If propNames.Contains("DefaultCompressionQuality") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultCompressionQuality"), QuoteString(propDefaults.GetProperty("DefaultCompressionQuality").ToString()))
				End If
				'should be int
				If propNames.Contains("MaxRecordCount") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("maxRecordCount"), QuoteString(propDefaults.GetProperty("MaxRecordCount").ToString()))
				End If
				'should be int
				If propNames.Contains("MaxMosaicImageCount") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("maxMosaicImageCount"), QuoteString(propDefaults.GetProperty("MaxMosaicImageCount").ToString()))
				End If
				'should be int
				If propNames.Contains("MaxDownloadImageCount") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("maxDownloadImageCount"), QuoteString(propDefaults.GetProperty("MaxDownloadImageCount").ToString()))
				End If
				'should be int
				If propNames.Contains("MaxDownloadSizeLimit") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("MaxDownloadSizeLimit"), QuoteString(propDefaults.GetProperty("MaxDownloadSizeLimit").ToString()))
				End If
				'should be int
				If propNames.Contains("AllowedFields") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedFields"), QuoteString(propDefaults.GetProperty("AllowedFields").ToString()))
				End If
				'string
				If propNames.Contains("AllowedMosaicMethods") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedMosaicMethods"), QuoteString(propDefaults.GetProperty("AllowedMosaicMethods").ToString()))
				End If
				'string
				If propNames.Contains("AllowedItemMetadata") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedItemMetadata"), QuoteString(propDefaults.GetProperty("AllowedItemMetadata").ToString()))
				End If
				'string
				If propNames.Contains("AllowedMensurationCapabilities") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("AllowedMensurationCapabilities"), QuoteString(propDefaults.GetProperty("AllowedMensurationCapabilities").ToString()))
				End If
				'string
				If propNames.Contains("DefaultCompressionTolerance") Then
					sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultCompressionTolerance"), QuoteString(propDefaults.GetProperty("DefaultCompressionTolerance").ToString()))
					'string                    
					'sBuilder.AppendFormat("{0}: {1},", QuoteString("downloadDir"), QuoteString(@"c:\temp"));//string
					'sBuilder.AppendFormat("{0}: {1},", QuoteString("virutalDownloadDir"), QuoteString(@"http://localhost/temp");//string
				End If
			ElseIf sourceType <> esriImageServiceSourceType.esriImageServiceSourceTypeCatalog Then
				'not iscdef
				sBuilder.AppendFormat("{0}: {1},", QuoteString("allowedCompressions"), QuoteString("None,JPEG,LZ77"))
				sBuilder.AppendFormat("{0}: {1},", QuoteString("maxImageHeight"), QuoteString("4100"))
				'should be int     
				sBuilder.AppendFormat("{0}: {1},", QuoteString("maxImageWidth"), QuoteString("15000"))
				'should be int
				sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultResamplingMethod"), QuoteString("0"))
				'should be int
				sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultCompressionQuality"), QuoteString("75"))
				'should be int
				sBuilder.AppendFormat("{0}: {1},", QuoteString("defaultCompressionTolerance"), QuoteString("0.01"))
				'should be int
				Dim measure As IMensuration = New MensurationClass()
				measure.Raster = DirectCast(rasterDataset, IRasterDataset2).CreateFullRaster()
				Dim mensurationCaps As String = ""
				If measure.CanMeasure Then
					mensurationCaps = "Basic"
				End If
				If measure.CanMeasureHeightBaseToTop Then
					mensurationCaps += ",Base-Top Height"
				End If
				If measure.CanMeasureHeightBaseToTopShadow Then
					mensurationCaps += ",Base-Top Shadow Height"
				End If
				If measure.CanMeasureHeightTopToTopShadow Then
					mensurationCaps += ",Top-Top Shadow Height"
				End If
					'string
				sBuilder.AppendFormat("{0}: {1},", QuoteString("AllowedMensurationCapabilities"), QuoteString(mensurationCaps))
			End If

			'sBuilder.AppendFormat("{0}: {1},", QuoteString("dEM"), QuoteString(@"c:\elevation\elevation.tif"));                
			'sBuilder.AppendFormat("{0}: {1},", QuoteString("supportsOwnershipBasedAccessControl"), QuoteString("true"));
			'sBuilder.AppendFormat("{0}: {1},", QuoteString("allowOthersToUpdate"), QuoteString("true"));               
			'sBuilder.AppendFormat("{0}: {1},", QuoteString("allowOthersToDelete"), QuoteString("true"));
			'sBuilder.AppendFormat("{0}: {1},", QuoteString("cacheOnDemand"), QuoteString("false"));
			'sBuilder.AppendFormat("{0}: {1},", QuoteString("isCached"), QuoteString("false"));
			'sBuilder.AppendFormat("{0}: {1},", QuoteString("ignoreCache"), QuoteString("true"));
			'sBuilder.AppendFormat("{0}: {1},", QuoteString("useLocalCacheDir"), QuoteString("false"));
			'sBuilder.AppendFormat("{0}: {1},", QuoteString("clientCachingAllowed"), QuoteString("false"));


			sBuilder.AppendFormat("{0}: {1},", QuoteString("colormapToRGB"), QuoteString("false"))
			sBuilder.AppendFormat("{0}: {1},", QuoteString("returnJPGPNGAsJPG"), QuoteString("false"))
			sBuilder.AppendFormat("{0}: {1},", QuoteString("allowFunction"), QuoteString("true"))
			Dim rasterFunctions As String = ""
			sBuilder.AppendFormat("{0}: {1},", QuoteString("rasterFunctions"), QuoteString(rasterFunctions).Replace("\", "\\"))
			Dim rasterTypes As String = ""
			sBuilder.AppendFormat("{0}: {1}", QuoteString("rasterTypes"), QuoteString(rasterTypes).Replace("\", "\\"))

			sBuilder.Append("},")
			Dim enableWCS As Boolean = True
			Dim enableWMS As Boolean = True
			sBuilder.AppendFormat("{0}: {1}", QuoteString("extensions"), "[{""typeName"":""WCSServer"",""enabled"":""" & enableWCS & """,""capabilities"":null,""properties"":{}},{""typeName"":""WMSServer"",""enabled"":""" & enableWMS & """,""capabilities"":null,""properties"":{""title"":""WMS"",""name"":""WMS"",""inheritLayerNames"":""false""}}")
			sBuilder.Append("],")
			sBuilder.AppendFormat("{0}: {1}", QuoteString("datasets"), "[]")
			sBuilder.Append("}")
			Dim postcontent As String = HttpUtility.UrlEncode(sBuilder.ToString())
			Dim token As String = GenerateAGSToken_RESTAdmin()
			postcontent = "service=" & postcontent & "&startAfterCreate=on&f=pjson&token=" & token
			Dim content As [Byte]() = Encoding.UTF8.GetBytes(postcontent)
			request.ContentLength = content.Length
			request.ContentType = "application/x-www-form-urlencoded"
			request.Method = "POST"
			Dim requestStream As Stream = request.GetRequestStream()
			requestStream.Write(content, 0, content.Length)
			requestStream.Close()
			Dim response As WebResponse = request.GetResponse()
			Dim responseStream As Stream = response.GetResponseStream()
			Dim reader As New StreamReader(responseStream)
			Dim result As String = reader.ReadToEnd()
			Console.WriteLine("create service:" & serviceName & " result:" & result)
			'wait for 5 seconds to reduce latency issue
			'System.Threading.Thread.Sleep(5000);
			Return result.Contains("success")
		Catch exc As Exception
			Console.WriteLine(exc.Message)
			Return False
		End Try
	End Function
	Private Shared Function QuoteString(input As String) As String
		Return """" & input & """"
	End Function
	Private Shared Function DeQuoteString(input As String) As String
		If input.StartsWith("""") Then
			Return input.Substring(1, input.Length - 2).Trim()
		Else
			Return input
		End If
	End Function

	#End Region

End Class