Author Archives: Simon

About Simon

I am a GIS devloper working mostly with C#.Net - but am quite ambivalent about preference to programming languages - they all serve a purpose in their own little way!

Add raster layer from map service in ArcGIS Portal


User needs to add one or many raster layers into ArcGIS Pro from a map service.  Default behaviour only allows adding the complete map service and all it’s constituent rasters (of which there could be dozens).

First of all map services need to be enabled with WMS before you can even start thinking about adding discrete layers.  This is done via ArcGIS Server:

In Portal, as admin, you need to make sure both the map service and the WMS service are given the correct permissions to your end users – you must do this for both services!

The Code

Note the code below is referencing the WMS url not the standard map service.

string wmsUrl = "https://gisportal.foocompany.local/ags/services/fooservice/MapServer/WMSServer";
string rasterName = "fooRasterName";  
var serverConnection = new CIMInternetServerConnection { URL = wmsUrl };
var connection = new CIMWMSServiceConnection { ServerConnection = serverConnection };
connection.ServerConnection.User = "fooUser";
connection.ServerConnection.Password = "barPassword";
connection.LayerName = layerName;
RasterLayer rasterLayer = null;
await QueuedTask.Run(() =>
    var layer = LayerFactory.Instance.CreateLayer(connection, MapView.Active.Map);


This method seems clunky becuase you have the overhead of having to create a WMS service and not just being able to stick with standard map services.

After asking ESRI why when trying to add a raster layer nothing happens – they replied by saying “it’s by design” – with no further explanation. To me it makes no sense – why not have it behave the same way when adding feature based layers from a map service.


Modeless vs Modal Dialog

Simple explanation of the differences between modeless and modal dialogs.

win1 dialog

Show() – Modeless

  • Doesn’t stop executing.
  • Can show and create several windows and interact all at once.

ShowDialog() – Modal

  • Intercepts code execution.
  • Stops interaction with other windows.
  • Ideal for presenting the user with a choice that must be made before continuing.
  • When a form is closed the form object and all it’s control information still exists until the referencing variable goes out of scope:

Form1 myForm = new Form1();
myForm .ShowDialog();
....lots of code here.....

Quick Start Using Massive and PostGreSQL

Most of the documentation for using Massive is OK – there are one or two things you might need to be aware of when you start a project from scratch – and I mean from scratch.  Follow these steps and you shouldn’t go far wrong.


OK – so I have a PostgreSQL database installed (called “geodb”) and I have table called Report.

report table

As you can see it’s just some basic text and ids, nothing special here.

I create a new Windows application using Visual Studio, it could be a console app – it’s not important – just something to get you started.

Install Npgsql

You will need to have the Npgsql installed/referenced into your project, so you can at least “talk” to the database, and Massive needs this to be able to do this.  In the Package Manager Console just type (bear in mind the version will probably be different when you read this):

PM> Install-Package Npgsql -Version 3.0.4


Modify App.config

This is always mentioned – but you do have to modify you App.config for you project.  This is so Massive can find your database connection string and it knows which dll to load in to talk to the database – which is the Npgsql.dll in this case.


Your App.Config should look like this:


The connection string goodness and DbProviderFactories section detailing the dll – make sure the Version tallies up with the one in your project – just get the properties of the dll from the References treeview in the project.


Create Massive Class

Quite easy to do – you can add Massive by Nuget, or just copy paste the code from GitHub for the PostgreSQL version and make a new class file.

Create Report Class

Create a new class – inheriting DynamicModel, passing in the name of database, the table and the primary key.

public class Report: DynamicModel
    public Report() : base("geodb", "report", "id")


Test Code

Make an instance of the class by copying the code below:

var table = new Report();
foreach (var rec in table.All())
     / /These apply to the column names.
     Console.WriteLine("{0} {1} ",,;


Put the code in a Main() method or button click event to just test the code and it should just all work fairy easily.

Find all layers of a type recursively in ArcMap

This code snippit will allow you to return all layers of a type you specify from an mxd.  Very handy code:

public List<ILayer> LoopThroughLayersOfSpecificUID(IMap map, String layerCLSID, bool searchRecursive)
/// The different layer GUID's and Interface's are:
/// "{AD88322D-533D-4E36-A5C9-1B109AF7A346}" = IACFeatureLayer
/// "{74E45211-DFE6-11D3-9FF7-00C04F6BC6A5}" = IACLayer
/// "{495C0E2C-D51D-4ED4-9FC1-FA04AB93568D}" = IACImageLayer
/// "{65BD02AC-1CAD-462A-A524-3F17E9D85432}" = IACAcetateLayer
/// "{4AEDC069-B599-424B-A374-49602ABAD308}" = IAnnotationLayer
/// "{DBCA59AC-6771-4408-8F48-C7D53389440C}" = IAnnotationSublayer
/// "{E299ADBC-A5C3-11D2-9B10-00C04FA33299}" = ICadLayer
/// "{7F1AB670-5CA9-44D1-B42D-12AA868FC757}" = ICadastralFabricLayer
/// "{BA119BC4-939A-11D2-A2F4-080009B6F22B}" = ICompositeLayer
/// "{9646BB82-9512-11D2-A2F6-080009B6F22B}" = ICompositeGraphicsLayer
/// "{0C22A4C7-DAFD-11D2-9F46-00C04F6BC78E}" = ICoverageAnnotationLayer
/// "{6CA416B1-E160-11D2-9F4E-00C04F6BC78E}" = IDataLayer
/// "{0737082E-958E-11D4-80ED-00C04F601565}" = IDimensionLayer
/// "{48E56B3F-EC3A-11D2-9F5C-00C04F6BC6A5}" = IFDOGraphicsLayer
/// "{40A9E885-5533-11D0-98BE-00805F7CED21}" = IFeatureLayer
/// "{605BC37A-15E9-40A0-90FB-DE4CC376838C}" = IGdbRasterCatalogLayer
/// "{E156D7E5-22AF-11D3-9F99-00C04F6BC78E}" = IGeoFeatureLayer
/// "{34B2EF81-F4AC-11D1-A245-080009B6F22B}" = IGraphicsLayer
/// "{EDAD6644-1810-11D1-86AE-0000F8751720}" = IGroupLayer
/// "{D090AA89-C2F1-11D3-9FEF-00C04F6BC6A5}" = IIMSSubLayer
/// "{DC8505FF-D521-11D3-9FF4-00C04F6BC6A5}" = IIMAMapLayer
/// "{34C20002-4D3C-11D0-92D8-00805F7C28B0}" = ILayer
/// "{E9B56157-7EB7-4DB3-9958-AFBF3B5E1470}" = IMapServerLayer
/// "{B059B902-5C7A-4287-982E-EF0BC77C6AAB}" = IMapServerSublayer
/// "{82870538-E09E-42C0-9228-CBCB244B91BA}" = INetworkLayer
/// "{D02371C7-35F7-11D2-B1F2-00C04F8EDEFF}" = IRasterLayer
/// "{AF9930F0-F61E-11D3-8D6C-00C04F5B87B2}" = IRasterCatalogLayer
/// "{FCEFF094-8E6A-4972-9BB4-429C71B07289}" = ITemporaryLayer
/// "{5A0F220D-614F-4C72-AFF2-7EA0BE2C8513}" = ITerrainLayer
/// "{FE308F36-BDCA-11D1-A523-0000F8774F0F}" = ITinLayer
/// "{FB6337E3-610A-4BC2-9142-760D954C22EB}" = ITopologyLayer
/// "{005F592A-327B-44A4-AEEB-409D2F866F47}" = IWMSLayer
/// "{D43D9A73-FF6C-4A19-B36A-D7ECBE61962A}" = IWMSGroupLayer
/// "{8C19B114-1168-41A3-9E14-FC30CA5A4E9D}" = IWMSMapLayer

List<ILayer> layers = new List<ILayer>();

if (map == null || layerCLSID == null)
return layers;

ESRI.ArcGIS.esriSystem.IUID uid = new ESRI.ArcGIS.esriSystem.UIDClass();
uid.Value = layerCLSID; // Example: "{E156D7E5-22AF-11D3-9F99-00C04F6BC78E}" = IGeoFeatureLayer
IEnumLayer enumLayer = map.get_Layers(((ESRI.ArcGIS.esriSystem.UID)(uid)), searchRecursive); // Explicit Cast
ILayer layer = enumLayer.Next();

while (!(layer == null))
layer = enumLayer.Next();
catch (System.Exception ex)
MessageBox.Show("No layers of type: " + uid.Value.ToString() + " " + ex.Message);
return layers;


Deleting corrupt rasters from ArcSDE

Sometimes data gets corrupted when trying to load data into ArcSDE.  This can be problematic as standard and recommended processes to remove data from ArcSDE cannot be used (i.e. ArcCatalog).

Manual deletion must be undertaken by going to the database directly and deleting all record of the data in the SDE system tables and the actual business table itself.  Yes, this is scary!, but if you do some defensive SQL to create “backups” of the data you are about to delete then you should be OK.  Also check that you have made a backup of your database too for “belt and braces”.

Featured image

In SDE Schema:

SELECT rastercolumn_id FROM raster_columns WHERE table_name = <table name>
SELECT layer_id FROM layers WHERE table_name = <table name>

The results from above will be used in the schema where the faulty raster is stored so make a note of the rastercolumn_id and the layer_id  !!

CREATE TABLE table_registry_bak AS SELECT * FROM table_registry WHERE table_name = <table name>;
DELETE FROM table_registry WHERE table_name = <table name>;

CREATE TABLE layers_bak AS SELECT * FROM layers WHERE table_name = <table name>;
DELETE FROM layers WHERE table_name = <table name>;

CREATE TABLE raster_columns_bak AS SELECT * FROM raster_columns WHERE table_name = <table name>;
DELETE FROM raster_columns WHERE table_name = <table name>;

CREATE TABLE gdb_objectclasses_bak AS SELECT * FROM gdb_objectclasses WHERE NAME = <table name>;
DELETE FROM gdb_objectclasses WHERE NAME = <table name>;

CREATE TABLE geometry_columns_bak AS SELECT * FROM geometry_columns WHERE f_table_name = <table name>;
DELETE FROM geometry_columns WHERE f_table_name = <table name>;

CREATE TABLE column_registry_bak AS SELECT * FROM column_registry WHERE table_name = <table name>;
DELETE FROM column_registry WHERE table_name = <table name>;

In the faulty data schema:

CREATE TABLE DEM_20M_0042_LUTE_ON_SP_HS_bak AS SELECT * FROM <table name>;
DROP TABLE <table name>;

CREATE TABLE sde_aux_<rastercolumn_id>_bak AS SELECT * FROM sde_aux_<rastercolumn_id>;
DROP TABLE sde_aux_<rastercolumn_id>;

CREATE TABLE sde_bnd_<rastercolumn_id>_bak AS SELECT * FROM sde_bnd_<rastercolumn_id>;
DROP TABLE sde_bnd_<rastercolumn_id>;

CREATE TABLE sde_blk_<rastercolumn_id>_bak AS SELECT * FROM sde_blk_<rastercolumn_id>;
DROP TABLE sde_blk_<rastercolumn_id>;

CREATE TABLE sde_ras_<rastercolumn_id>_bak AS SELECT * FROM sde_ras_<rastercolumn_id>;
DROP TABLE sde_ras_<rastercolumn_id>;

CREATE TABLE f4707_bak AS SELECT * FROM f<layer_id> ;
DROP TABLE f<layer_id>;

CREATE TABLE s<layer_id>_bak AS SELECT * FROM s<layer_id>;
DROP TABLE s<layer_id>;

Once you have run these sql commands, check everything is ok in ArcCatalog, then delete all tables with “_bak” to clean everything up.

Simple Interface Example in C#

The following shows a simple example of how Interfaces can be very useful in C#.  Here SomeOtherClass doesn’t care what’s passed in as long as it conforms to ILog, then it will be able to call the Log function – this is truly polymorphic guys!


public interface ILog
 void Log(string text);
public class FileLog : ILog
 public void Log(string text)
  // write text to a file
public class DatabaseLog : ILog
 public void Log(string text)
  // write text to the database
public class SomeOtherClass
 private ILog _logger;
 public SomeOtherClass(ILog logger)
  // I don't know if logger is the FileLog or DatabaseLog
  // but I don't need to know either as long as its implementing ILog
  this._logger = logger;
  logger.Log("Hello World!");

Sublime Text 2 – Open Chrome Tab on Build

Simple to create automatically open a Chrome tab when editing HTML and wanting to see your changes.

  1. Select New Build System from the menus – see below:


2.  Get rid of the default text and replace with where you have installed the Google Chrome executable – it should look something like this (be sure to put in double backslashes for the filepath and put in “$file” after the filepath too:


3.  Save it as something sensible like “Chrome”.

4.  Then in the Build System menu (see first screenshot), you should see “Chrome” appear, select this.  Now press Ctrl+B or select Build from the Tools menu and it should open a new tab in Chrome.

Pretty easy.