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

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

  #End Region

    <STAThread()> _
    Public Shared Sub Main(ByVal args As String())

        Try
            '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()
                    Exit Select
                Case "delete"
                    DeleteService()
                    Exit Select
                Case "start"
                    StartService()
                    Exit Select
                Case "stop"
                    StopService()
                    Exit Select
                Case "pause"
                    PauseService()
                    Exit Select
                Case "list"
                    ListServices()
                    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(host) Then
        Return
      End If
      Dim sourceType As esriImageServiceSourceType = GetSourceType(sourcePath)
      'connect to ArcGIS Server and create configuration
      Dim gisServerConnection As IGISServerConnection = New GISServerConnectionClass()
      gisServerConnection.Connect(host)
      Dim soAdmin As IServerObjectAdmin = gisServerConnection.ServerObjectAdmin
      Dim soConfig As IServerObjectConfiguration = DirectCast(soAdmin.CreateConfiguration(), IServerObjectConfiguration)

      'set general service parameters
      soConfig.Name = configName
      soConfig.TypeName = "ImageServer"
      soConfig.StartupType = esriStartupType.esriSTAutomatic
      soConfig.IsPooled = True
      soConfig.IsolationLevel = esriServerIsolationLevel.esriServerIsolationHigh
      soConfig.MinInstances = 1
      soConfig.MaxInstances = 2
      Dim propertySet_Recycle As IPropertySet = soConfig.RecycleProperties
            propertySet_Recycle.SetProperty("Start", "00:00")
            propertySet_Recycle.SetProperty("Interval", "86400")
      Dim propertySet As IPropertySet = soConfig.Properties
      If sourceType = esriImageServiceSourceType.esriImageServiceSourceTypeCatalog Then
        '(sourceDataPath.ToLower().EndsWith(".iscdef"))
        propertySet.SetProperty("ServiceDefinition", sourcePath)
      Else
        propertySet.SetProperty("Path", sourcePath)
      End If
            propertySet.SetProperty("SupportedImageReturnTypes", "URL")
      'virtual directory
      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


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

      'enable web capabilities
      Dim soConfig2 As IServerObjectConfiguration2 = DirectCast(soConfig, IServerObjectConfiguration2)
      soConfig2.Info.SetProperty("WebEnabled", "true")
      If sourceType = esriImageServiceSourceType.esriImageServiceSourceTypeMosaicDataset Then
        soConfig2.Info.SetProperty("WebCapabilities", "Image,Catalog,Metadata,Download,Pixels")
      Else
                soConfig2.Info.SetProperty("WebCapabilities", "Image,Metadata")
      End If

            'enable wcs, assume data has spatial reference
            soConfig2.ExtensionEnabled("WCSServer") = True
            Dim propertySetWCS As IPropertySet = soConfig2.ExtensionInfo("WCSServer")
            propertySetWCS.SetProperty("WebEnabled", True)

            'enable wms
            soConfig2.ExtensionEnabled("WMSServer") = True
            Dim propertySetWMS As IPropertySet = soConfig2.ExtensionInfo("WMSServer")
            propertySetWMS.SetProperty("WebEnabled", "true")

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

            If soAdmin.GetConfigurationStatus(configName, "ImageServer").Status = esriConfigurationStatus.esriCSStarted Then
                Console.WriteLine("{0} on {1} has been configured and started.", configName, host)
            Else
                Console.WriteLine("{0} on {1} was configured but can not be started, please investigate.", configName, host)
            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(host) Then
        Return
      End If
      Dim soAdmin As IServerObjectAdmin = gisServerConnection.ServerObjectAdmin
      If Not ValidateConfigName(soAdmin, configName, host) Then
        Return
      End If
      soAdmin.DeleteConfiguration(configName, "ImageServer")
      Console.WriteLine("{0} on {1} was deleted successfully.", configName, host)
    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(host) Then
        Return
      End If
      Dim soAdmin As IServerObjectAdmin = gisServerConnection.ServerObjectAdmin
      If Not ValidateConfigName(soAdmin, configName, host) Then
        Return
      End If
      soAdmin.StartConfiguration(configName, "ImageServer")
      If soAdmin.GetConfigurationStatus(configName, "ImageServer").Status = esriConfigurationStatus.esriCSStarted Then
        Console.WriteLine("{0} on {1} was started successfully.", configName, host)
      Else
        Console.WriteLine("{0} on {1} couldn't be started, please investigate.", configName, host)
      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(host) Then
        Return
      End If
      Dim soAdmin As IServerObjectAdmin = gisServerConnection.ServerObjectAdmin
      If Not ValidateConfigName(soAdmin, configName, host) Then
        Return
      End If
      soAdmin.StopConfiguration(configName, "ImageServer")
      If soAdmin.GetConfigurationStatus(configName, "ImageServer").Status = esriConfigurationStatus.esriCSStopped Then
        Console.WriteLine("{0} on {1} was stopped successfully.", configName, host)
      Else
        Console.WriteLine("{0} on {1} couldn't be stopped, please investigate.", configName, host)
      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(host) Then
        Return
      End If
      Dim soAdmin As IServerObjectAdmin = gisServerConnection.ServerObjectAdmin
      If Not ValidateConfigName(soAdmin, configName, host) Then
        Return
      End If
      If (soAdmin.GetConfigurationStatus(configName, "ImageServer").Status = esriConfigurationStatus.esriCSStopped) Then
        Console.WriteLine("{0} on {1} is currently stopped --- not paused.", configName, host)
        Return
      End If
      soAdmin.PauseConfiguration(configName, "ImageServer")
      If soAdmin.GetConfigurationStatus(configName, "ImageServer").Status = esriConfigurationStatus.esriCSPaused Then
        Console.WriteLine("{0} on {1} was paused successfully.", configName, host)
      Else
        Console.WriteLine("{0} on {1} couldn't be paused, please investigate.", configName, host)
      End If
    Catch exc As Exception
      Console.WriteLine("Error: {0}", exc.Message)
    End Try
  End Sub


  Private Shared Sub ListServices()
    Try
      If Not ConnectAGS(host) Then
        Return
      End If
      Dim soAdmin As IServerObjectAdmin = gisServerConnection.ServerObjectAdmin
      Dim enumConfigs As IEnumServerObjectConfiguration = soAdmin.GetConfigurations()
      enumConfigs.Reset()
      Dim soConfig As IServerObjectConfiguration = enumConfigs.[Next]()
      Console.WriteLine("ArcGIS Server {0} has the following image services:", host)
      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
      gisServerConnection = New GISServerConnectionClass()
      gisServerConnection.Connect(host)
      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 ConfigName
  ''' </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 ValidateConfigName(soAdmin As IServerObjectAdmin, ByRef configName 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() = configName.ToUpper() Then
        configName = soConfig.Name
        Return True
      End If
      soConfig = enumConfigs.[Next]()
    End While
    Console.WriteLine("Configuration {0} on {1} can not be found.", configName, 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 < 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 args.Length > 6 Then
        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 args.Length > 8 Then
        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"}
    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 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 license As String = System.Environment.GetEnvironmentVariable("ARCLICENSE")
        Dim status As esriLicenseStatus = aoInit.Initialize(esriLicenseProductCode.esriLicenseProductCodeArcView)
    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(ByVal args As String())
        For i As Integer = 2 To args.Length - 1
            Select Case args(i)
                Case "-h"
                    host = args(System.Threading.Interlocked.Increment(i))
                    Exit Select
                Case "-d"
                    sourcePath = args(System.Threading.Interlocked.Increment(i))
                    Exit Select
                Case "-n"
                    configName = 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(ByVal sourcePath As String) As esriImageServiceSourceType
        If sourcePath.ToLower().EndsWith(".iscdef") Then
            Return esriImageServiceSourceType.esriImageServiceSourceTypeCatalog
        ElseIf sourcePath.ToLower().EndsWith(".lyr") Then
            Return esriImageServiceSourceType.esriImageServiceSourceTypeLayer
        Else
            Dim fileInfo As FileInfo = 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>
    ''' <returns>a raster dataset object</returns>
    Private Shared Sub OpenRasterDataset(ByVal path As String, ByVal 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 ".mdb"
                    factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.AccessWorkspaceFactory")
                    workspaceFactory = CType(Activator.CreateInstance(factoryType), IWorkspaceFactory)
                    workspace = workspaceFactory.OpenFromFile(path, 1)
                    rasterWorkspaceEx = CType(workspace, IRasterWorkspaceEx)
                    rasterDataset = rasterWorkspaceEx.OpenRasterDataset(rasterDSName)
                    Exit Select
                Case ".gdb"
                    factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory")
                    workspaceFactory = CType(Activator.CreateInstance(factoryType), IWorkspaceFactory)
                    workspace = workspaceFactory.OpenFromFile(path, 1)
                    rasterWorkspaceEx = CType(workspace, IRasterWorkspaceEx)
                    rasterDataset = rasterWorkspaceEx.OpenRasterDataset(rasterDSName)
                    Exit Select
                Case ".sde"
                    factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.SdeWorkspaceFactory")
                    workspaceFactory = CType(Activator.CreateInstance(factoryType), IWorkspaceFactory)
                    workspace = workspaceFactory.OpenFromFile(path, 1)
                    rasterWorkspaceEx = CType(workspace, IRasterWorkspaceEx)
                    rasterDataset = rasterWorkspaceEx.OpenRasterDataset(rasterDSName)
                    Exit Select
                Case Else
                    factoryType = Type.GetTypeFromProgID("esriDataSourcesRaster.RasterWorkspaceFactory")
                    workspaceFactory = CType(Activator.CreateInstance(factoryType), IWorkspaceFactory)
                    workspace = workspaceFactory.OpenFromFile(path, 1)
                    Dim rasterWS As IRasterWorkspace = CType(workspace, IRasterWorkspace)
                    rasterDataset = rasterWS.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 configuration utility.")
        Console.WriteLine()
        Console.WriteLine("Usage. <>: required parameter; |: pick one.")
        Console.WriteLine("isconfig -o publish -h <host> -d <datapath> -n <configName>")
        Console.WriteLine("isconfig -o <delete|start|stop|pause> -h <host> -n <configName>")
        Console.WriteLine("isconfig -o <list> -h <host>")
    End Sub
#End Region

End Class