List of ArcObjects posts:
- Introduction
- Getting Started
- Extending the Framework
- Workspace
- Workspace Provider
- Workspace is Down
- Licensing
- Com Releaser
- Cursors and IsRecycling
- WorkspaceUtils
- Multithreading
- Mocking
List of ArcObjects posts:
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:
(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:
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:
Checking if the workspace is running:
If it’s down recreate it (and if it can’t be recreated throw an exception):
You can also look at the full code here.
Hopefully next time the DB is down it will just recreate IWorksapce…
Resources:
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:
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):
Where:
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:
2. Using Sde Connection String provided:
3. Using a Cad file:
4. Using either GDB or MDB file paths:
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
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:
Computer Management –> Services And Applications –> Service:
By Default the service will be called “ArcSde Service(esri_sde)”:
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.
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:
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
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:
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:
This is to set the default values of my organization:
(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:
The output of this method looks like this:
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
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
Looking into the FeatureServer link you will find in the bottom “Supported Operations: Query” where you can test the Feature service queries:
Some points:
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?
ArcObjects Forum: Publish MXD to server in ArcObjects C#
Keywords: MSD, ArcObjects, ArcGis Server, ESRI
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”:
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
Whenever you change a layer in the DB or publish a new server you might notice that the REST API will not automatically update. In order for it to update you might need to clear the REST API cache.
There are several ways to do so:
ArcGis Server comes with a REST API admin page, which can be found here:
http://SERVERNAME/ArcGIS/rest/admin
Logging in to this page gives you the Clear Cache Options:
The page has a bunch of options for clearing the catch semi-automatically:
What you need to do is simply click on the "Clear Cache Now" several times (at some version of the Server one time was not enough…).
Disadvantages:
1. You need to have the admin user/password in order to clear the cache
2. The process needs to be done manually.
3. If you have multiple server you will have to do so for each server
ESRI gives another way which is to use a generated token and then you can simply call a link whenever you want to clear the cache. More on that here (ESRI refers to this method as “the easy way”).
Disadvantages:
1. Different token for each server
2. The process needs to be manually set at each server
The problem with all of these methods is that you can’t really use them to install servers, at my company we have more servers then flies and having to clear the cache after each installation is tedious work that is often forgotten (and when it is forgotten I find myself wasting hours trying to debug the “problem”). So I decided to write a console application that does the clearing of the cache for me. This idea actually came from this forum post, the only problem was that the code didn’t really work for me…
So I tweaked it a bit with WebRequest and the end result is this:
And HttpUtils.PostRequest looks like:
I think that this way is the best since all I need is the server name, the admin user and it’s password. I can do it remotely and I can do it automatically after each deploy. The only thing that is not so good is the using of the clear password (and lets be honest here the next step is putting the call to the console application in a batch file for the development environment and giving that file to the rest of the team so that a hacker…).
Source code can be found at my Codeplex project, here (the code has a few more useful commands like publishing a MSD file, changing the connection of MSD file etc.).
Resources:
Clearing the ArcGIS Services Directory cache “the easy way” – ArcGIS Server Blog
Clear cache through code by demand – ArcGis Server Forum
Hanselman: HTTP POSTs and HTTP GETs with WebClient and C# and Faking a PostBack
Keywords: ESRI,ArcGIS Server,REST API
This post is the forth post in my ArcObjects series.
As I have written in ArcObjects: Introduction, using ArcObjects is one way of performing CRUD operations against a Spatial DB (with SDE layer on top) and the way to do that is by using the intefaces of WorkspaceClass.
ESRI definition for the Workspace is this:
A Workspace is a container of spatial and non-spatial datasets such as feature classes, raster datasets and tables. It provides methods to instantiate existing datasets and to create new datasets.
Mine is a bit more simple, the WorkspaceClass is the class that does all the “work” within the “space” it is defined to work at. The Space section of the definition can be a DB Sde, File Geodatabase, Cad files and anything else ArcDesktop applications can open. The Work section refers to any basic action that can be done with ArcDesktop applications.
For example: IFeatureWorkspace allows you to create a new Feature Table, open an existing Feature Table and with the help of IFeatureClass perform CRUD operations on that table.
One important note however is that you cannot create a new instance of it, it must be returned for you – the next post will be on getting the workspace.
As you can see the WorkspaceClass implements a lot of interfaces, the good news is you don’t need most of them (I have only found usage for two of them).
What do you need then?
So how do we use it?
This actually the only thing you can do with just the IFeatureWorkspace, but if you actually want to do something like return all the feature in a layer you need to use the IFeatureClass:
So what do we have here?
line 4: creates the IQueryFilter – this goes into the where clause of the SQL we will send to DB.
line 5: we get the IFeatureClass of the layer
line 6 and 9: this is important ArcObjects use Com which is a resource, every resource we use must be disposed. At kine 6 we create the disposing class and in line 9 we attach the cursor to that disposing class, when line 17 arrives the using statement will call the Dispose method for ComReleaser and automatically dispose our cursor. More on cursor and disposing of the resources will be written in a later post.
line 8: creates the cursor that we will use to iterate the rows of the DB, IsRecyclingCursorInGetFeatures defines the way the cursor works (more on that on a later post)
lines 12-16: iterating the data
And that’s it.
A friend of mine called me a few months ago and asked for advice on implementing a simple mapping application on the web. He remembered I worked on a mapping project and wanted my help.
His client wanted him to implement a web based site with a map of the client stores. The map should be customizable, meaning you could add items and remove them. And when I write map I mean a map of the interior of the store not it’s location in the world.
Now all the mapping options I know of are bulky and not quite simple but I promised him I will look it up for him.
The first thing I did was Googling “web simple map” got myself this results:
But the options were neither simple nor easy to implement.
Then I got back to the requirements – mapping a store. That is almost like my B.A. final project of internal design for apartments, that had a 3D look to it but the design mode was at it’s base a 2D painter. And that is what the requirements wanted a Painter that has only basic drawing tools like placing certain items on the canvas.
The background for this application will be an image of the store. Saving the canvas will save the items’ locations in the canvas, while loading will repaint them in place.
And the best part there is already an open source Painter application around in Java Script Called Canvas Paint (a copy of Microsoft’s Paint application in the Web) the script is also included here:
The File->Save option allow saving the image on the server…
In the end my friend decided to create a demo using this site, which allows you to place points on an image:
(when the mouse is over a point you get a tooltip with an image)
If the client likes it he will actually program something similar.
So, I guess what I am saying is check out the requirements before you jump to implementing a GIS solution. Mapping for the client doesn’t always mean using world coordinates (and often the client won’t even know what world coordinates mean).
Keywords: mapping, simple, paint
I know its been a while…
The past month or so I have been mostly working on bug fixes since we were deploying a new version. But enough about that, ESRI gave us this little award for Special Achievement in GIS 2011.
We haven’t gone to the award ceremony but we did a little photo session of our own:
From left to right: Michael Halperin (the GIS team leader), Gur Hanan (GIS specialist), Vered Kestenbaum (GIS specialist, in charge of all installations with ArcGis Desktop), Me (mostly server side GIS programming), Felix Shkolnik (our UI GURU, since he arrived the UI has changed colors and shapes more times than I though possible – now it looks great), Eyal Perez (our manager, also the name on the award).
Remember I wrote UI GURU? Well it took less than an hour for Felix to create the real photo:
I am told this photo has made its rounds in Systematics (the local vendor for ESRI in Israel).
One of the projects I work on is a windows service that listens to the Tibco bus and handles messages. Since it always runs we decided to use it for another purpose – periodic calls. Calls that need to be done every few seconds/minutes.
One of those calls is for handling traffic load reports and another for handling some messages in bulk (we receive thousands of those messages every minute and required to handle them every 15 seconds). The traffic load synching is added on startup but the bulk handler is added later.
For that purpose I created a nice little class called PeriodicCaller that has a List of PeriodicCall (Action, when was last called, TimeSpan between calls). PeriodicCaller starts a new thread that calls the list using foreach.
The problem we faced though was that sometimes the Add operation failed, and we were unlucky enough to receive this exception:
System.InvalidOperationException was unhandled
Message=Collection was modified; enumeration operation may not execute.
Source=mscorlib
StackTrace:
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.Enumerator.MoveNext()
at ListAddAndForEach.PeriodicCaller.Caller()
Why is luck a factor? Because this only happens when the Add is called in the middle of the foreach loop.
The fix is quite easy instead of using a foreach loop use a for loop (and just ignore Resharper’s warning:
because sometimes they are just wrong…).
Continued from Adding Google Streets View, using Google API V3 instead of V2
Or actually “ops…”
During the testing stage for our application my Team Leader installed the application on another server and tried to run it. He got this pop-up for his trouble:
Message from webpage
This web site needs a different Google Maps API key. A new key can be
generated at http://code.google.com/apis/maps/signup.html.
Now while using the original code I had a problem with one line of code:
More precisely the part of: key=DioG342lPJG3WTn3zmQqebsjVg
But I thought to myself – “It works…”
Well the bite in the ass has come…
So what is this key?
It seems Google Map API V2 requires each domain to be registered and then to use an API key. I didn’t want to do that because we had too many servers with different domains (with new environments added all the time).
Getting such a key though is as easy as registering here, but be sure to first read the FAQ (more on that in my previous post).
In Google API V3 they removed the need for API key, but they also changed the API so that the current JavaScript code doesn’t work.
So I rewrote it to this:
Much more simple code:
getPanoramaByLocation – returns status OK for coordinates that have Street View 50 (set in a parameter) meters from them.
Be sure though to place (line 20):
Before calling StreetViewPanorama or you will get an “Out of stack space” error (I opened a bug on this but since the work around as fairly simple it probably won’t be fixed any time soon…).
One last warning the functionality is almost the same. The only difference I could find is that V3 hasn’t implemented Full Screen mode yet (unknown when it will be added or if it will) where V2 has it out of the box.
V2:
V3:
Seems almost the same…
Code sample can be found in my CodePlex Project, or directly here.
Edit (13/09/2011): Fixed Firefox bug in JavaScript
Keywords: Silverlight, Map, Google Street View, Google Map API