Subscribe Now: Feed Icon

Monday, December 26, 2011

ArcObjects: TOC

List of ArcObjects posts:

  1. Introduction
  2. Getting Started
  3. Extending the Framework
  4. Workspace
  5. Workspace Provider
  6. Workspace is Down
  7. Licensing
  8. Com Releaser
  9. Cursors and IsRecycling
  10. WorkspaceUtils
  11. Multithreading
  12. Mocking

 

IceRocket Tags:

ArcObjects: Workspace is Down

This post is the sixth post in my ArcObjects series.

This is a direct continuation from my post ArcObjects: Workspace Provider.

 

Back in March our DB was down over the night and unlike all the other systems ours didn't just resume work after the DB was brought up, it needed the team’s involvement.

The Exception we got was:

System.Runtime.InteropServices.COMException was unhandled

  HelpLink=esri_csGeoDatabase.hlp

  Message=Failure to access the DBMS server [Microsoft SQL Server Native Client 10.0: Communication link failure] [SERVER.SCHEMA.LAYER_NAME]

  Source=esriDataSourcesGDB.SdeWorkspace.1

  ErrorCode=-2147155559

  StackTrace:

       at ESRI.ArcGIS.Geodatabase.IFeatureClass.Search(IQueryFilter filter, Boolean Recycling)

  InnerException:

 

So I recreated the error by restarting the "SQL Server (MSSQLSERVER)" service in our DB with some special code.

 

Symptoms:

1.       The IWorkspace status:

((IWorkspace) _workspace).Exists();

                Returns true

2.       Then I started looking at other places like ESRI’s diagrams. One of the diagrams:

image

(Not mine EDN's)

IWorkspaceStatus sounded a bit off to me that it is under WorkspaceFactory and not under Workspace but the real problem was what was written in the documentation. There are no implementations of this according to EDN…

But I found another interface IWorkspaceFactoryStatus, managed to point it to my workspace and got back:

((ESRI.ArcGIS.Geodatabase.IWorkspaceFactoryStatus  )workspaceFactoryTemp).PingWorkspaceStatus((ESRI.ArcGIS.Geodatabase.IWorkspace)_workspace)

{System.__ComObject}

    [System.__ComObject]: {System.__ComObject}

    ConnectionStatus: esriWCSAvailable

    Workspace: {System.__ComObject}

 

I just thought to myself how can it possibly be Available, until I look at the documentation at esriWorkspaceConnectionStatus:

image

Available doesn't mean it's up - just that it was lost and now is available. And I was sure it meant something else… (Couldn’t they name it something like LostAndNowAvailable or AvailableToReconnect? – Available just does not cut it!!!).

 

The end result looks like this:

  1. if (!IsWorkspaceRunning(_workspace))
  2. {
  3.     ReactivateWorkspace();
  4.     InitializeWorkspaceUtils(_workspace);
  5. }
  6. return _workspaceUtils;

Checking if the workspace is running:

  1. private bool IsWorkspaceRunning(IWorkspace workspace)
  2. {
  3.     IWorkspaceFactoryStatus workspaceFactory = new SdeWorkspaceFactoryClass();
  4.     return workspaceFactory.PingWorkspaceStatus(workspace).ConnectionStatus == esriWorkspaceConnectionStatus.esriWCSUp && workspace.Exists();
  5. }

If it’s down recreate it (and if it can’t be recreated throw an exception):

  1. private void ReactivateWorkspace()
  2. {
  3.     IWorkspaceFactoryStatus workspaceFactory = new SdeWorkspaceFactoryClass();
  4.     var status = workspaceFactory.PingWorkspaceStatus(_workspace);
  5.     if (status.ConnectionStatus != esriWorkspaceConnectionStatus.esriWCSDown)
  6.     {
  7.         _workspace = workspaceFactory.OpenAvailableWorkspace(status);
  8.     }
  9.  
  10.     //try to create it again:
  11.     _workspace = CreateWorkspace(_connectionString);
  12.     status = workspaceFactory.PingWorkspaceStatus(_workspace);
  13.  
  14.     if (status.ConnectionStatus == esriWorkspaceConnectionStatus.esriWCSDown)
  15.     {
  16.         throw new ApplicationException("The Connection to the database was lost. Please contact your system administrators.");
  17.     }
  18. }

You can also look at the full code here.

 

Hopefully next time the DB is down it will just recreate IWorksapce…

 

Resources:

The forum post I wrote

ArcObjects: Workspace Provider

This post is the fifth post in my ArcObjects series.

As I mentioned in my previous post you cannot create a workspace you have to receive it from some place. That place is called the WorkspaceFactory (or as usual IWorkspaceFactory).  Now since getting the workspace is useful and usually only done once we put it in a singleton class named WorkspaceProvider.

As can be seen in the IWorkspaceFactory documentation there are many implementation of this interface. The implementation differ in the Space where the workspace is doing it’s work:

  1. SdeWorkspaceFactory – works on a Sde DB
  2. CadWorkspaceFactory – works on CAD files
  3. AccessWorkspaceFactory and FileGDBWorkspaceFactory – work on File based Geodatabases

These classes provide the interface to connect to the Space the same way ArcDesktop tools do so by the Open method. You can either use a file containing the connection (created in ArcCatalog), use IPropertySet a list containing the connection information (see here for details) or by using connection string (the other options just use this option behind the scene).

Sde connection string are separated to two categories (more details in one of my previous posts: ArcSDE: Connection to the Geodatabase):

  • Regular connection: "SERVER={0};INSTANCE={4};USER={2};PASSWORD={3};Database={1};VERSION=SDE.Default"
  • Direct connection: "SERVER={0};INSTANCE=sde:{5}:{0};USER={2};PASSWORD={3};Database={1};VERSION=SDE.Default"

Where:

  • {0} – Server name
  • {1} – Database name
  • {2} – User name
  • {3} – password
  • {4} – Sde service number
  • {5} – Type of the server (i.e. sqlserver)
  • If you need to you can also add the Sde version

As you can see direct connection doesn’t use the Sde service number, that is because it doesn’t use the Sde service (it does all the work at the client). Most times you won’t need to change the Server type so that’s out as well. My code only uses Direct Connection string (since ESRI recommends using it).

 

In my experience most applications will use only one IWorkspace – the one connecting them to the application Sde. For that reason WorkspaceProvider uses DefaultDbConfigSection which is both a Configuration Section and a Connection String builder (I use it for both the Sde and regular DB Connection string). To prevent unnecessary creation of IWorkspace objects WorkspaceProvider will also store the last IWorkspace created and the connection string used to create it.

As it is the only public methods needed for this class are:

1. Using Sde Connection String from web/app.config file:

  1. public WorkspaceUtils GetWorkspace()
 

2. Using Sde Connection String provided:

  1. public WorkspaceUtils GetWorkspace(string sdeConnectionString)

3. Using a Cad file:

  1. public CadWorkspaceUtils GetCadWorkspace(string path)

4. Using either GDB or MDB file paths:

  1. public FileWorkspaceUtils GetFileWorkspace(string filePath)

The full code can be found here.

 

Most of the code is self-explanatory except one part – getting a cached Workspace. Now you might think this is the most simple part but when taking into account that sometimes connections fail, servers are down and Murphy is constantly prowling than you must be ready for that “What If…”. I will write more on this in one of the next posts.

The rest of the code is pretty much self-explanatory and can be found in my CodePlex Project, or directly here.

 

Resources:

MSDN: How to: Create Custom Configuration Sections Using ConfigurationSection

Sunday, December 18, 2011

ArcSDE: Connection to the Geodatabase

When connection to a database SDE there are two ways to achieve that:

(From ESRI site the ArcCatalog connection screen)

1. Regular connection using Server, Service (enter the SDE service number), database, user(optional), password(optional)

The regular way uses a service on the database machine which must be running. The service can be found in:

Right click on My Computer –> Manage:

image

Computer Management –> Services And Applications –> Service:

image

By Default the service will be called “ArcSde Service(esri_sde)”:

image

As you can see I am not using the regular way (the service is not marked as started). For both 10 and 9.3.1 ESRI advices not to use it this way since it does all it’s work on the DB machine.

Note: if you are using several sde services than the Service port will differ than the default of 5151. If you are unsure about the number than look in the DB server at services file (located at: c:\Windows\System32\drivers\etc and has no extension). The file contains lines for services, their port and connection protocol:

esri_sde    5151/tcp    #ArcSDE for SqlServer

2. Direct Connection using Server, Service, database, user(optional), password(optional)

The difference in the connection is only in Service, for example in SQL Server: “sde:sqlserver:<sql_server_instance>” (for any other server use this ESRI reference the forth step).

This connection doesn’t use the SDE service. It connects directly to the DB and does all it’s work on the client. If you are using only this connection type then I advise you to change the “ArcSde Service(esri_sde)” to run Manually instead of Automatic – it just means that at startup the service won’t be turned on.

 

Managing SDE connection in a developer team

I have created all my SDE connection but now my team mate Bob needs a connection, What do I do?

Well I usually save the connections in one of the team’s network folders with a bat file called install connections. Here is how I do that:

  1. Copy all the connections from %APPDATA%\ESRI\Desktop10.0\ArcCatalog to your network folder.
  2. Create a bat file with:

xCopy *.sde %APPDATA%\ESRI\Desktop10.0\ArcCatalog /I

 

(The /I is for creating the sub folder when they don’t exist (like when you never opened ArcCatalog…))

 

Resources:

ESRI: Geodatabase connections in ArcGIS Desktop

ESRI: Preparing database connection files

ESRI: What is a direct connection to a geodatabase in DB2?

Help about xCopy

MSD tools: Changing Connection and Publishing

Last month I got a new assignment to develop a tool that changes the layers’ connection in a MXD file and publish it in ArcGis Server. It is fairly easy to do it using ArcMap but we have too many environments/servers and whatever we can automate should be automated.

Since then the team went to a Systematics Event (ESRI local provider) where they talked about the new stuff in version 10.1, namely that publishing will only support MSD files (not MXD files) – so the task got changed a bit. For more information on MSD functionality and Performance considerations.

Finding how to change the connection of the layers was easy enough with the IMSDHelper interface:

  1. private const bool UseRelativePath = true;
  2. private const bool ValidateLayerConnection = false;
  3.  
  4. /// <summary>
  5. /// Changes the SDE connection string for all the layers in the MSD file
  6. /// </summary>
  7. /// <param name="msdFilePath"></param>
  8. /// <param name="connectionString"></param>
  9. /// <param name="resultMsdFile">result file is relative path</param>
  10. public static void ChangeConnection(string msdFilePath, string connectionString, string resultMsdFile)
  11. {
  12.     IMSDHelper helper = new MSDHelper();
  13.     helper.Open(msdFilePath);
  14.     var maps = helper.GetMaps();
  15.     for (var i = 0; i < maps.Count; i++)
  16.     {
  17.         var layers = helper.GetLayers(maps.Element[i]);
  18.         for (var j = 0; j < layers.Count; j++)
  19.         {
  20.             helper.PutWorkspaceConnectionStringInLayer(layers.Element[j], connectionString, ValidateLayerConnection);
  21.         }
  22.     }
  23.     helper.SaveAs(resultMsdFile, UseRelativePath);
  24. }

We simply iterate through all the maps and all the inner layers and change the connection to the given one.

 

But what about Publishing the MSD automatically? This proved to be a bit more problematic. It was fairly easy to find a Python script using arcPy that publishes MSD files. But less so on ArcObjects code, in the end I found this forum post which led me to this code (just run it through Google Translate since it’s in Chinese). The code looks like this:

  1. public static void PublishToServer(string mapFilePath, string serverName, string serviceName)
  2. {
  3.     IGISServerConnection gisServerConnection = new GISServerConnectionClass();
  4.     gisServerConnection.Connect(serverName);
  5.     var serverObjectAdmin = gisServerConnection.ServerObjectAdmin;
  6.     var configuration = (IServerObjectConfiguration2)serverObjectAdmin.CreateConfiguration();
  7.  
  8.     // release the name of the Service, required
  9.     configuration.Name = serviceName;
  10.     // release the type of service, such as: MapServer, GeocodeServer
  11.     configuration.TypeName = ServiceConfigurationTypeName;
  12.     configuration.Description = serviceName;
  13.  
  14.     // Service Description
  15.     SetDefaultServerConfigurations(configuration, mapFilePath, serverName);
  16.  
  17.     // add service to the Server
  18.     serverObjectAdmin.AddConfiguration(configuration);
  19.  
  20.     // start the service
  21.     serverObjectAdmin.StartConfiguration(configuration.Name, configuration.TypeName);
  22. }

This is to set the default values of my organization:

private static void SetDefaultServerConfigurations(IServerObjectConfiguration2 configuration, string mapFilePath, string serverName)
{
    var properties = configuration.Properties;
    // Set the path of the file
    properties.SetProperty("FilePath", mapFilePath);
    // image output directory
    properties.SetProperty("outputdir", "c:\\arcgisserver\\arcgisoutput");
    // image output virtual path
    properties.SetProperty("VirtualOutPutDir", "http://" + serverName + "/arcgisoutput");
    // image type supported by
    properties.SetProperty("SupportedImageReturnTypes", "URL");

(there are more settings that can be found here)

 

I found that it is best to look at existing services, for that I added the capability of getting your service settings in XML format:

  1. public static string GetServiceConfiguration(string serverName, string serviceName)
  2. {
  3.     IGISServerConnection gisServerConnection = new GISServerConnectionClass();
  4.     gisServerConnection.Connect(serverName);
  5.     var serverObjectAdmin = gisServerConnection.ServerObjectAdmin;
  6.  
  7.     var configuration = (IServerObjectConfiguration4)serverObjectAdmin.GetConfiguration(serviceName, ServiceConfigurationTypeName);
  8.     
  9.     return configuration.Serialize();
  10. }

The output of this method looks like this:

  1. <ServerObjectConfiguration>
  2.   <Description>PublishDemoIi</Description>
  3.   <Properties>
  4.     <FilePath>C:\Install\MsdUtils\Demo.msd</FilePath>
  5.     <outputdir>c:\arcgisserver\arcgisoutput</outputdir>
  6.     <VirtualOutPutDir>http://server/arcgisoutput</VirtualOutPutDir>
  7.     <SupportedImageReturnTypes>URL</SupportedImageReturnTypes>
  8.     <MaxImageHeight>2048</MaxImageHeight>
  9.     <MaxRecordCount>50000</MaxRecordCount>
  10.     <MaxBufferCount>100</MaxBufferCount>
  11.     <MaxImageWidth>2048</MaxImageWidth>
  12.     <IsCached>false</IsCached>
  13.     <CacheOnDemand>false</CacheOnDemand>
  14.     <IgnoreCache>false</IgnoreCache>
  15.     <ClientCachingAllowed>true</ClientCachingAllowed>
  16.     <CacheDir>c:\arcgisserver\arcgiscache\GtmPublishDemoIi</CacheDir>
  17.     <SOMCacheDir>c:\arcgisserver\arcgiscache</SOMCacheDir>
  18.     <UseLocalCacheDir>true</UseLocalCacheDir>
  19.   </Properties>
  20.   <Extension>
  21.     <TypeName>FeatureServer</TypeName>
  22.     <Enabled>true</Enabled>
  23.     <Properties>
  24.       <EnableZDefaults>false</EnableZDefaults>
  25.       <ZDefaultValue>0</ZDefaultValue>
  26.     </Properties>
  27.     <Info>
  28.       <WebEnabled>true</WebEnabled>
  29.       <SupportsMSD>true</SupportsMSD>
  30.       <WebCapabilities>Query</WebCapabilities>
  31.     </Info>
  32.   </Extension>
  33.  
  34.   <Extension>
  35.     <TypeName>...</TypeName>
  36.     <Enabled>false</Enabled>
  37.     <Properties>
  38.     </Properties>
  39.     <Info>
  40.     </Info>
  41.   </Extension>
  42.  
  43.   <Info>
  44.     <WebEnabled>true</WebEnabled>
  45.     <WebCapabilities>Map,Query,Data</WebCapabilities>
  46.   </Info>
  47.   <IsPooled>true</IsPooled>
  48.   <MinInstances>1</MinInstances>
  49.   <MaxInstances>2</MaxInstances>
  50.   <InstancesPerContainer>1</InstancesPerContainer>
  51.   <WaitTimeout>60</WaitTimeout>
  52.   <IdleTimeout>-1</IdleTimeout>
  53.   <UsageTimeout>600</UsageTimeout>
  54.   <CleanupTimeout>30</CleanupTimeout>
  55.   <ServiceKeepAliveInterval>-1</ServiceKeepAliveInterval>
  56.   <StartupTimeout>300</StartupTimeout>
  57.   <Isolation>high</Isolation>
  58.   <StartupType>automatic</StartupType>
  59. </ServerObjectConfiguration>

As you can see the properties in the XML correspond perfectly with the properties settings.

 

To test the creation of the service you can look at ArcGis Server Manager:

http://ServerName/ArcGIS/manager/default.aspx

ArcGisServerManagementService

Where you can tweak the settings (as you can see I had 5 tries till I got it right…).

Also you can test the service using the REST API :

http://ServerName/ArcGIS/rest/services

ArcGisRestService

Looking into the FeatureServer link you will find in the bottom “Supported Operations: Query” where you can test the Feature service queries:

FeatureServiceQuery

 

Some points:

  1. Using PublishToServer needs MSD file located on the server.
  2. In order to use PublishToServer user must be an admin on the server (otherwise the call gisServerConnection.ServerObjectAdmin would fail)
  3. You must clear ArcGis rest API cache before using the service (or you won’t see it in the rest/services url) – for doing that automatically see my previous post: Clearing ArcGIS Server REST API Cache

I have posted the complete tool in my Codeplex project: ArcGisServerTools, MsdUtils, ArcGisServerUtils.

 

Resources:

ArcGis Server Forum: Promote map service from one server stage to another in automated fashion?

Findleaf - Chinese Blog code

ArcObjects Forum: Publish MXD to server in ArcObjects C#

 

Keywords: MSD, ArcObjects, ArcGis Server, ESRI

Sunday, December 11, 2011

Active Window Loses Focus problem (Full Screen minimizes)

For the past several years I have been having a problem with my home computer (Windows XP), the problem is not so severe just annoying (though I guess for some people it will be much more severe). My problem? from time to time the application I work on losses it’s focus for a second and then either:

a. gets it back (when it’s in windowed state) 

b. another application gets the focus (when it’s full screen applications).

My solution to the problem was using only windowed applications but it is too annoying when watching movies or sometimes impossible when playing games.

From time to time I would search the web for solutions and find forums that advise people to open Task Manager (or other similar applications) and just see what application is stealing the focus – the problem is you need to be fairly fast to catch the bugger (especially when games and movies demand your full attention). Other solutions were with specific applications that caused the problem like AVG anti virus (in one of its old versions). I have tried formatting the computer but the problem returned (meaning it must be some application I always use).

So I have decided to fix (or at least find the problematic application) myself. I first found a windows function that partially does what I wanted – GetForegroundWindow, then searching for it with C# I found a solution at StackOverflow site a bunch of invoke methods that return the current focused window information, all that was left was wrapping it in a console application and using it.

In the end running the little app at home found the problem:

27/11/2011 20:22:10:C:\WINDOWS\System32\rasautou.exe -> Connecting Cables012...

For the past several years my computer has been the dial up computer for the internet. Cables012 is that connection. Thinking to solve connection problems I enabled “Establish a dial-up connection whenever a computer on my network attempts to access the Internet”:

BeforeInternetConnection

I thought to myself that this option will just reconnect to the internet when the connection is down, well it does that and also steals the windows focus whenever it feels like and at exactly midnight it also activate what I like to call “Blinking Window Mode” when at least one window will appear in the general top left area of the screen and disappear before you can read what it says…

Well the fix was easy enough just uncheck this option and restart the connection. This whole thing was a surprise since I was sure I had some kind of funky spyware app installed which caused all of this…

I have added the source code for this little app to my Codeplex project, and also a release exec (for the non programmers who reach this site).

 

Keywords: Windows, Full Screen, Focus

IceRocket Tags: ,,