Running MapServer and mapscript on IIS 7

This is just a note (mainly to self) on a couple of  tweaks you have to make to IIS 7 in order to run Mapserver on IIS 7. Last couple of days I was banging my head against a wall trying to figure out why I was getting this error on a web site I was developing:

Could not load file or assembly ‘mapscript_csharp’ or one of its dependencies. An attempt was made to load a program with an incorrect format.

I was certain all required dlls were there and the application was running fine from within Visual Studio 2010. It was only when I was publishing it that the error was occurring. And it was also working fine on an IIS 6 server.

As it turned out it was an IIS 7 setting (as it invariably is). Apparently IIS does not allow by default 32-bit applications in the Default Application pool. So all I had to do was to go to IIS Manager, and then select DefaultAppPool->Advanced Settings:

image

After changing the [Enable32-Bit] Applications to True all was well and I was a happy bunny again.

However, while I was investigating the above problem, I tried to run mapserver in cgi mode just to make sure all my dlls were correct. I was immediately hit by another couple of issues (admittedly due to my very thin knowledge on IIS 7).

The first one was how to enable CGI apps. This is pretty straight forward:

On IIS Manager select the machine node (the name of your machine) on the left and then click on the ISAPI and CGI restrictions icon

image

On the ISAPI and CGI restrictions page, select the [Add] action and in the displayed dialog enter the path of your mapserv.exe executable along with a name:

image

That would have sorted you would think- right? Well, not quite. You see, my mapserv.exe file was under the bin folder of my website (where all the other mapserver dlls were located) and when I tried to run the mapserv.exe I got this error:

HTTP Error 404.8 – Not Found

The request filtering module is configured to deny a path in the URL that contains a hiddenSegment section.

IIS again. To ‘fix’ this (although not sure you want to do this on a permanent basis), is to click on the [Request Filtering] icon for your Web application:

image

You should see a list containing all the hidden folders and files (aka segments). Select bin and click on [Remove] on the Actions list.

But that’s not all. The last thing you need to do, is to add execute permission on the Web app. To do this, select the Handler Mappings icon, select Feature Permissions for in the Actions list and click on the Execute box.

image

You should now be able to run mapserv as CGI and get this soothing message:

image

All done. Hope this helps someone!.

Drawing selected features in Mapserver with mapscript

For those of you who are using Mapserver, you may have noticed a somewhat "weird" behaviour when drawing selected features that have been defined with combined symbols (multiple styles within the same class).
Let me explain: When you define multiple styles for a class in a layer in the mapfile and then you select/highlight the feature using mapscript, the highlight color only seems to apply to the last style used and not the whole (combined) symbol. For example if you got a class defined for a point layer as :

CLASS
STYLE
COLOR 138 138 138
SYMBOL 'triangle'
SIZE 15
END
STYLE
COLOR 255 0 0
SYMBOL "point"
SIZE 5
END
END

and where the "triangle" and "point" symbols are defined as:

SYMBOL
NAME "triangle"
TYPE VECTOR
POINTS
0 1
0.5 0
1 1
0 1
END
FILLED TRUE
STYLE
1 25 1 25
END
END
SYMBOL
NAME "point"
TYPE ELLIPSE
POINTS
1 1
END
FILLED TRUE
END

only the "Point" symbol will be drawn in the highlight color instead of both symbols. Since the last symbol is usually the smallest size, its not even visible the end user what has been highlighted. This also applies for line and polygon features. The situation is even worst for point features that are only defined with a bitmap image only. In these cases the highlight feature is not even getting drawn. This has been raised as Ticket #3190 with the mapserver team and is scheduled for the 6.0 release of Mapserver.

In the meantime though I have found an alternative way to highlight features, which gives much greater flexibility in defining and drawing selections. Basically, I am ignoring the QUERYMAP settings and dont use the mapObj.DrawQuery() method. Instead I define my own "selection" layers, one for each feature type (point, line, polygon) in the mapfile. Then, once I got a handle on the the selected recordset, I loop through it and draw the selected features one by one based on the corresponding "selection layer" using the shapeObj.draw() function. There is probably a performance hit doing this but so far I haven’t noticed it  even with largish (100’s of features) selections.

So how is this implemented? First I define my selection layers as:

# ———————————————————-
#    SELECTION LAYERS
# ———————————————————-
#
# Layer to draw line selections
LAYER
        NAME "selectedline"
        STATUS ON
        TYPE LINE
  TRANSPARENCY ALPHA
        TEMPLATE nofile.html
        CLASS
            STYLE
    COLOR 16 238 246
    OUTLINECOLOR 255 0 0
    WIDTH 5
   END
        END
END
# Layer to draw point selections
  LAYER
        NAME "selectedpoint"
        STATUS ON
        TYPE POINT
  TRANSPARENCY ALPHA
        TEMPLATE nofile.html
        CLASS
   SYMBOL "point"
   COLOR 16 238 246
   SIZE 10
        END
END
# Layer to draw polygon selections
LAYER
        NAME "selectedpoly"
        STATUS ON
        TYPE POLYGON
  TOLERANCE 10
        TRANSPARENCY ALPHA
        TEMPLATE nofile.html
        CLASS
   COLOR 16 238 246
     END
END

The code (in mapscript C#) to draw the selected features is:

//Draw the map to get a handle on the imageObj
imageObj image=aMapObj.draw();
layerObj active_layer = aMapObj.getLayer(active_layer_index);
//Open the layer
active_layer.open();
//Get the selection
resultCacheObj results = active_layer.getResults();
//Loop through selection and draw each feature
for (int iResultsNo = 0; iResultsNo < results.numresults; iResultsNo++)
{
int shapeInd = results.getResult(iResultsNo).shapeindex;
shapeObj shape = active_layer.getFeature(shapeInd, -1);
if (shape.type == (int)MS_SHAPE_TYPE.MS_SHAPE_POINT)
{ shape.draw(aMapObj, aMapObj.getLayerByName("selectedpoint"), image); }
else if (shape.type == (int)MS_SHAPE_TYPE.MS_SHAPE_LINE)
{ shape.draw(aMapObj, aMapObj.getLayerByName("selectedline"), image); }
else if (shape.type == (int)MS_SHAPE_TYPE.MS_SHAPE_POLYGON)
{ shape.draw(aMapObj, aMapObj.getLayerByName("selectedpoly"), image); }
}

where active_layer_index is the layer index in the mapfile.

Obviously, you can experiment with CLASS element in the the selection layers and create much more interesting effects when drawing the selections.
Hope this will help someone!