如何使用mapscript处理图层模板以响应WMS GetFeatureInfo请求

时间:2011-02-18 13:00:06

标签: c# mapserver

我正在尝试使用c#mapscript处理GetFeaturInfo WMS请求。在使用mapscript之前,我们的软件将WMS请求传递给IIS上托管的CGI映射服务器。这处理了与每个查询图层关联的html模板,并在模板中替换了许多令牌以获取数据。

我们不能使用mapserver cgi实现,所以我试图通过C#mapscript机制使用mapscript重新实现这个机制。

我到目前为止的代码摘要在这里。这个问题是对processQueryTemplate的调用导致抛出AccessViolation异常。

public string GetFeatureInfoFromWMS(NameValueCollection WMSqueryString)
{
    //Set the projection library environment variable used by mapscript.dll
    Environment.SetEnvironmentVariable("PROJ_LIB", ProjectionLibraryPath);

    string output = string.Empty;

    try
    {
        using (mapObj map = new mapObj(MapFile))
        {
            //Add aditional layer specific params - ie location of plugins etc
            ProcessLayers(map, WMSqueryString);

            map.web.metadata.set("wms_onlineresource", WMSOnlineResourceURL);

            string xVal = WMSqueryString["X"];
            string yVal = WMSqueryString["Y"];

            if (xVal == null || yVal == null)
            {
                throw new ArgumentNullException("The X or Y point value has not been suppplied in the GetFeatureInfo request");
            }

            double pointX = 0.0;
            double pointY = 0.0;

            try 
            {           
                pointX = Convert.ToDouble(xVal);
                pointY = Convert.ToDouble(yVal);
            }
            catch (Exception e)
            {
                throw new ArgumentException("The X or Y point value supplied in the GetFeatureInfo request is not a valid decimal",e);
            }

            string layersQS = WMSqueryString["QUERY_LAYERS"];

            if (layersQS == null)
            {
                throw new ArgumentNullException("The QUERY_LAYERS parameter of the WMS GetFeatureInfo request is not specified correctly");
            }

            //Load the parameters from the wms request into the map
            using (OWSRequest request = new OWSRequest())
            {
                for (int i = 0; i < WMSqueryString.Count; i++)
                {
                    request.setParameter(WMSqueryString.GetKey(i), WMSqueryString.Get(i));
                }

                string wmsVersion = WMSqueryString["VERSION"];

                if (wmsVersion == null || wmsVersion == string.Empty) wmsVersion = DEFAULT_WMS_VERSION;

                map.loadOWSParameters(request, wmsVersion);
            }

            //Reproject X & Y pixel co-ordinates in map co-ordintes.
            double minX = map.extent.minx;
            double maxX = map.extent.maxx;
            double geoX = minX + ((pointX / (double)map.width) * (maxX - minX));

            double minY = map.extent.miny;
            double maxY = map.extent.maxy;
            double geoY = maxY - ((pointY / (double)map.height) * (maxY - minY));

            string[] queryLayers = layersQS.Split(',');

            using (pointObj point = new pointObj(geoX, geoY, 0, 0))
            {
                foreach (string layerName in queryLayers)
                {
                    using (layerObj layer = map.getLayerByName(layerName))
                    {
                        int queryResult = layer.queryByPoint(map, point, (int)MS_QUERY_MODE.MS_QUERY_SINGLE, -1);
                    }
                }
            }

            map.prepareQuery();

            string[] names = { "Token1" };
            string[] values = { "Value1" };

            //BANG!!!!!!
            output = map.processQueryTemplate(names, values, 10);
        }
        return output;
    }
    catch (Exception ex)
    {
        throw;
    }
}

关联的地图文件如下:

    MAP

#
# Start of map file
#
NAME esdm
STATUS ON
TEMPLATEPATTERN "."
SIZE 400 600
UNITS meters
EXTENT 0 0 800000 1200000

IMAGECOLOR 255 255 255
FONTSET fonts.txt
#DEBUG ON
IMAGETYPE PNG

  PROJECTION
        "init=epsg:27700"
  END


    OUTPUTFORMAT
        NAME "png"
        DRIVER "GD/PNG"
        IMAGEMODE RGBA
        MIMETYPE image/png
        EXTENSION png
        TRANSPARENT ON
    END

#  OUTPUTFORMAT
#    NAME "imagemap"
#    MIMETYPE text/html; driver=imagemap
#    DRIVER "imagemap"
#  END 



#
# Start of web interface definition (including WMS enabling metadata)
#
WEB

    METADATA
        "wms_title" "SQL mapping data"
        "wms_srs"  "EPSG:27700 EPSG:4326 EPSG:54004 EPSG:54005 EPSG:900913"
        "wms_feature_info_mime_type" "text/plain"
        "wms_include_items" "all"
    END
END

INCLUDE "mapSymbols.inc"

# BARSActions Point Layer
#-----------------------------------------------------------------------------------------
LAYER
  NAME "Actions"
MAXSCALEDENOM 100000000
MINSCALEDENOM 0
  METADATA        
    "wms_title"  "BARSActions"
    "wfs_title"  "BARSActions"
    "wms_srs"  "EPSG:27700"
  END
  CONNECTIONTYPE PLUGIN
  PLUGIN "SQLPlugin" 
  DATA "geom from MapLoadTest USING UNIQUE ActionId USING SRID=27700"
  FILTER "(OrgUnitId = 1 AND %ActionStatusID% AND %ActionTypeID% AND %AreaIDST(geom)%)"

  TYPE POINT
  STATUS ON
  TOLERANCE 50
  TEMPLATE "barsTemplate.htm"

  CLASS
    COLOR 0 0 255 
    OUTLINECOLOR 0 0 0
    SYMBOL 'star'
    SIZE 15
    #MAXSIZE 6
    #MINSIZE 3
  END # end of class object

  PROJECTION
        "init=epsg:27700"
  END
  DUMP True
END # end of layer object


# BARSActions Polygon Layer
#-----------------------------------------------------------------------------------------
LAYER
  NAME "ActionsPolygons"

MAXSCALEDENOM 100000000
MINSCALEDENOM 0
  METADATA        
    "wms_title"  "BARSActionsPolygons"
    "wfs_title"  "BARSActionsPolygons"
    "wms_srs"  "EPSG:27700"
  END
  CONNECTIONTYPE PLUGIN
  PLUGIN "SQLPlugin"
  DATA "geom from MapLoadTest USING UNIQUE ActionId USING SRID=27700"
  FILTER "(OrgUnitId = 2 AND ActionID = 200 AND %ActionStatusID% AND %ActionTypeID% AND %AreaIDST(geom)%)"

  TYPE POLYGON
  STATUS ON
  TOLERANCE 50
  TEMPLATE "barsTemplate.htm"

  CLASS
    COLOR 0 0 255 
    OUTLINECOLOR 0 0 0
  END # end of class object

  PROJECTION
        "init=epsg:27700"
  END
  DUMP True
END # end of layer object

END # Map File

映射文件中的各个项目都是标记化的(即sql插件位置和应用于数据的过滤器)这是通过在前一个方法中调用ProcessLayers来处理的。绘制地图时,此机制似乎不会导致任何问题。对queryByPoint的调用有效。它返回成功,针对sql db运行的查询返回预期数据。

我不确定从这里开始的地方以及从模板生成输出还需要做些什么。我期待调用processQueryTemplate来返回填充的模板。我也不太清楚prepareQuery应该做什么。

干杯

1 个答案:

答案 0 :(得分:1)

从未想过如何让模板发挥作用。但是我设法获取查询返回的形状的数据库ID。然后我使用这些来在其他地方准备HTML结果。

请注意,我正在使用map.querybypoint来处理存在图层组的情况(在这种情况下,图层组名称将作为wms请求中的图层名称出现。

/// <summary>
/// Handles a GetFeature info request and returns matching ActionID's.
/// </summary>
/// <param name="WMSqueryString">The WM squery string.</param>
/// <returns>A list of matching action ID's.</returns>
/// <exception cref="ArgumentNullException">Thrown if the X or Y point values are not supplied in the WMS GetFeatureInfo request</exception>
/// <exception cref="ArgumentException">Thrown in the X or Y point values supplied in the WMS GetFeatureInfo request cannot be converted to valid doubles</exception>
public List<int> GetFeatureInfoActionID(NameValueCollection WMSqueryString)
{
    //Set the projection library environment variable used by mapscript.dll
    Environment.SetEnvironmentVariable("PROJ_LIB", ProjectionLibraryPath);

    try
    {
        List<int> resultsList = new List<int>();

        using (mapObj map = new mapObj(MapFile))
        {
            ProcessLayers(map, WMSqueryString);

            map.web.metadata.set("wms_onlineresource", WMSOnlineResourceURL);

            //Load the parameters from the wms request into the map
            using (OWSRequest request = new OWSRequest())
            {
                for (int i = 0; i < WMSqueryString.Count; i++)
                {
                    request.setParameter(WMSqueryString.GetKey(i), WMSqueryString.Get(i));
                }

                string wmsVersion = WMSqueryString["VERSION"];

                if (wmsVersion == null || wmsVersion == string.Empty) wmsVersion = DEFAULT_WMS_VERSION;

                map.loadOWSParameters(request, wmsVersion);
            }

            string xVal = WMSqueryString["X"];
            string yVal = WMSqueryString["Y"];

            if (xVal == null || yVal == null)
            {
                throw new ArgumentNullException("The X or Y point value has not been suppplied in the GetFeatureInfo request");
            }

            double pointX = 0.0;
            double pointY = 0.0;

            try 
            {            
                pointX = Convert.ToDouble(xVal);
                pointY = Convert.ToDouble(yVal);
            }
            catch (Exception e)
            {
                throw new ArgumentException("The X or Y point value supplied in the GetFeatureInfo request is not a valid decimal",e);
            }

            //Reproject X & Y pixel co-ordinates in map co-ordintes.
            double minX = map.extent.minx;
            double maxX = map.extent.maxx;
            double geoX = minX + ((pointX / (double)map.width) * (maxX - minX));

            double minY = map.extent.miny;
            double maxY = map.extent.maxy;
            double geoY = maxY - ((pointY / (double)map.height) * (maxY - minY));

            MS_RETURN_VALUE queryResult;

            using (pointObj point = new pointObj(geoX, geoY, 0, 0))
            {
                queryResult = (MS_RETURN_VALUE)map.queryByPoint(point, (int)MS_QUERY_MODE.MS_QUERY_MULTIPLE, -1);
            }

            if (queryResult != MS_RETURN_VALUE.MS_SUCCESS)
            {
                return null;
            }

            map.prepareQuery();

            for (int layerIndex = 0; layerIndex < map.numlayers; layerIndex++)
            {
                using (layerObj layer = map.getLayer(layerIndex))
                {
                    int resultCount = layer.getNumResults();
                    if (resultCount > 0)
                    {
                        layer.open();

                        for (int resultIndex = 0; resultIndex < resultCount; resultIndex++)
                        {
                            using (resultCacheMemberObj resultCache = layer.getResult(resultIndex))
                            {
                                int actionID = resultCache.shapeindex;
                                if (actionID != 0 && resultsList.Contains(actionID) == false)
                                {
                                    resultsList.Add(actionID);
                                }
                            }
                        }

                        layer.close();
                    }
                }
            }

        }
        return resultsList;
    }
    catch (Exception ex)
    {
        throw;
    }
}