[mapguide-commits] r9256 - in trunk/MgDev: . Common/MapGuideCommon/Services Common/PlatformBase/Services Common/Stylization Server/src/Services/Feature Server/src/Services/Kml Server/src/Services/Mapping Server/src/Services/Rendering Server/src/Wfs Server/src/Wms UnitTest/TestData/Wfs UnitTest/WebTier/MapAgent/MapAgentForms Web/src/HttpHandler

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Sun Nov 26 14:22:40 PST 2017


Author: jng
Date: 2017-11-26 14:22:40 -0800 (Sun, 26 Nov 2017)
New Revision: 9256

Added:
   trunk/MgDev/Server/src/Services/Feature/OpGetWfsReader.cpp
   trunk/MgDev/Server/src/Services/Feature/OpGetWfsReader.h
   trunk/MgDev/Server/src/Services/Feature/WfsQueryAdapter.cpp
   trunk/MgDev/Server/src/Services/Feature/WfsQueryAdapter.h
   trunk/MgDev/Web/src/HttpHandler/WmsFeatureGeometry.cpp
   trunk/MgDev/Web/src/HttpHandler/WmsFeatureGeometry.h
Modified:
   trunk/MgDev/
   trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.h
   trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.h
   trunk/MgDev/Common/MapGuideCommon/Services/RenderingDefs.h
   trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.h
   trunk/MgDev/Common/PlatformBase/Services/FeatureDefs.h
   trunk/MgDev/Common/PlatformBase/Services/FeatureService.h
   trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.h
   trunk/MgDev/Common/Stylization/RendererStyles.h
   trunk/MgDev/Server/src/Services/Feature/FeatureOperationFactory.cpp
   trunk/MgDev/Server/src/Services/Feature/Makefile.am
   trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp
   trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.h
   trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj
   trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters
   trunk/MgDev/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp
   trunk/MgDev/Server/src/Services/Kml/ServerKmlService.cpp
   trunk/MgDev/Server/src/Services/Mapping/MappingUtil.cpp
   trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.cpp
   trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.h
   trunk/MgDev/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp
   trunk/MgDev/Server/src/Services/Rendering/RenderingOperationFactory.cpp
   trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp
   trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.h
   trunk/MgDev/Server/src/Wfs/OgcWfsService.config.awd
   trunk/MgDev/Server/src/Wms/1.0.0.xml.awd
   trunk/MgDev/Server/src/Wms/1.1.0.xml.awd
   trunk/MgDev/Server/src/Wms/1.1.1.xml.awd
   trunk/MgDev/Server/src/Wms/1.3.0.xml.awd
   trunk/MgDev/Server/src/Wms/OgcWmsService.config.awd
   trunk/MgDev/UnitTest/TestData/Wfs/WfsTest.dump
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/getfeatureinfowmsform.html
   trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/getfeaturewfsform.html
   trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj
   trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj.filters
   trunk/MgDev/Web/src/HttpHandler/HttpHandlerBuild.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpWfsGetFeature.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpWmsGetFeatureInfo.cpp
   trunk/MgDev/Web/src/HttpHandler/Makefile.am
   trunk/MgDev/Web/src/HttpHandler/OgcWmsServer.cpp
   trunk/MgDev/Web/src/HttpHandler/OgcWmsServer.h
   trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
   trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.h
   trunk/MgDev/Web/src/HttpHandler/WmsFeatureInfo.cpp
   trunk/MgDev/Web/src/HttpHandler/WmsFeatureInfo.h
   trunk/MgDev/Web/src/HttpHandler/WmsFeatureProperties.cpp
   trunk/MgDev/Web/src/HttpHandler/WmsFeatureProperties.h
Log:
Merge in RFC 163 sandbox


Property changes on: trunk/MgDev
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/2.4/MgDev:6749-6756,6777-6783,6785-6787,6789,6791-6794,6796-6801,6954-6962,6986-7006
/branches/2.6/MgDev:8276-8286,8288-8292,8297,8299,8301,8303,8314-8315,8318,8335,8340,8354-8355,8365,8373
/branches/3.0/MgDev:8658,8705,8710
/branches/3.1/MgDev:9026,9058-9059,9067-9068
/sandbox/VC140:8684-8759
/sandbox/adsk/2.6l:8727
/sandbox/adsk/3.0m:8563,8584,8607,8625,8694-8695
/sandbox/adsk/3.1n:8871,8895,8901,8912-8913,8921-8922,8942,9019-9020
/sandbox/jng/clean_json:8818-9180
/sandbox/jng/cmdline:9199-9217
/sandbox/jng/convenience_apis:8262-8268,8271-8363
/sandbox/jng/coordsys_mapagent:9231-9254
/sandbox/jng/createruntimemap:7486-7555
/sandbox/jng/dwftk:8321-8324,8328-8329,8331,8352
/sandbox/jng/geoprocessing:9205-9229
/sandbox/jng/geos34x:8256-8259
/sandbox/jng/php56x:8975-8985
/sandbox/jng/rfc155:8872-8884
/sandbox/jng/simplify:8814-9141
/sandbox/jng/tiling:8174-8208
/sandbox/jng/utfgrid:9179-9212
/sandbox/jng/v30:8212-8227
/sandbox/rfc94:5099-5163
   + /branches/2.4/MgDev:6749-6756,6777-6783,6785-6787,6789,6791-6794,6796-6801,6954-6962,6986-7006
/branches/2.6/MgDev:8276-8286,8288-8292,8297,8299,8301,8303,8314-8315,8318,8335,8340,8354-8355,8365,8373
/branches/3.0/MgDev:8658,8705,8710
/branches/3.1/MgDev:9026,9058-9059,9067-9068
/sandbox/VC140:8684-8759
/sandbox/adsk/2.6l:8727
/sandbox/adsk/3.0m:8563,8584,8607,8625,8694-8695
/sandbox/adsk/3.1n:8871,8895,8901,8912-8913,8921-8922,8942,9019-9020
/sandbox/jng/clean_json:8818-9180
/sandbox/jng/cmdline:9199-9217
/sandbox/jng/convenience_apis:8262-8268,8271-8363
/sandbox/jng/coordsys_mapagent:9231-9254
/sandbox/jng/createruntimemap:7486-7555
/sandbox/jng/dwftk:8321-8324,8328-8329,8331,8352
/sandbox/jng/geoprocessing:9205-9229
/sandbox/jng/geos34x:8256-8259
/sandbox/jng/ogc:9240-9255
/sandbox/jng/php56x:8975-8985
/sandbox/jng/rfc155:8872-8884
/sandbox/jng/simplify:8814-9141
/sandbox/jng/tiling:8174-8208
/sandbox/jng/utfgrid:9179-9212
/sandbox/jng/v30:8212-8227
/sandbox/rfc94:5099-5163

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -1473,7 +1473,38 @@
     return (MgByteReader*)cmd.GetReturnValue().val.m_obj;
 }
 
+MgFeatureReader* MgProxyFeatureService::GetWfsReader(MgResourceIdentifier* featureSourceId,
+                                                     CREFSTRING featureClass,
+                                                     MgStringCollection* requiredProperties,
+                                                     CREFSTRING srs,
+                                                     CREFSTRING filter,
+                                                     CREFSTRING sortCriteria)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knObject,                         // Return type expected
+                       MgFeatureServiceOpId::GetWfsReader_Id,       // Command Code
+                       6,                                           // No of arguments
+                       Feature_Service,                             // Service Id
+                       BUILD_VERSION(3,3,0),                        // Operation version
+                       MgCommand::knObject, featureSourceId,        // Argument#1
+                       MgCommand::knString, &featureClass,          // Argument#2
+                       MgCommand::knObject, requiredProperties,     // Argument#3
+                       MgCommand::knString, &srs,                   // Argument#4
+                       MgCommand::knString, &filter,                // Argument#5
+                       MgCommand::knString, &sortCriteria,          // Argument#6
+                       MgCommand::knNone);                          // End of argument
 
+    SetWarning(cmd.GetWarningObject());
+
+    Ptr<MgProxyFeatureReader> featReader = (MgProxyFeatureReader*)cmd.GetReturnValue().val.m_obj;
+
+    if (featReader != NULL)
+        featReader->SetService(this); // Feature reader on proxy side would store proxy service to call GetFeatures()
+
+    return SAFE_ADDREF((MgProxyFeatureReader*)featReader);
+}
+
 //////////////////////////////////////////////////////////////////
 MgBatchPropertyCollection* MgProxyFeatureService::GetFeatures(CREFSTRING featureReader)
 {

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ProxyFeatureService.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -1507,6 +1507,62 @@
                                 CREFSTRING namespacePrefix,
                                 CREFSTRING namespaceUrl);
 
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Retrieves feature information based on the supplied criteria.
+    ///
+    /// \note1
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader GetWfsReader(MgResourceIdentifier featureSourceId, string featureClass, MgStringCollection requiredProperties, string srs, string filter, int maxFeatures, string outputFormat, string sortCriteria);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader GetWfsReader(MgResourceIdentifier featureSourceId, string featureClass, MgStringCollection requiredProperties, string srs, string filter, int maxFeatures, string outputFormat, string sortCriteria);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader GetWfsReader(MgResourceIdentifier featureSourceId, string featureClass, MgStringCollection requiredProperties, string srs, string filter, int maxFeatures, string outputFormat, string sortCriteria);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param featureSourceId (MgResourceIdentifier)
+    /// The resource identifier defining the
+    /// location of the feature source in
+    /// the repository.
+    /// \param featureClass (String/string)
+    /// The feature class containing the features to retrieve.
+    /// \param requiredProperties (MgStringCollection)
+    /// The collection of properties to retrieve for each feature. If the
+    /// collection is null or empty, all properties will be retrieved.
+    /// \param srs (String/string)
+    /// The spatial reference system in which to return feature geometries
+    /// \param filter (String/string)
+    /// An XML string containing the definition for an OGC filter
+    /// \param maxFeatures (int)
+    /// The maximum number of features to retrieve. If the value is less
+    /// than or equal to zero, all features will be retrieved.
+    /// \param sortCriteria (String/string)
+    /// A string identifying the sort criteria
+    ///
+    /// \remarks
+    /// The purpose of this method, as opposed to GetWfsFeature is to return the base reader using the same input parameters
+    /// allowing for the caller to determine the desired output format and the desired content transformations required from 
+    /// the reader.
+    ///
+    /// The main use case for this method is for providing the base feature reader for outputting WFS GetFeature responses in 
+    /// formats other than GML
+    ///
+    /// \return
+    /// Returns an MgByteReader containing the requested feature information.
+    ///
+    /// \exception MgInvalidArgumentException
+    ///
+    MgFeatureReader* GetWfsReader(MgResourceIdentifier* featureSourceId,
+                                  CREFSTRING featureClass,
+                                  MgStringCollection* requiredProperties,
+                                  CREFSTRING srs,
+                                  CREFSTRING filter,
+                                  CREFSTRING sortCriteria);
+
     ////////////////////////////////////////////////////////////////////////////////
     /// \brief
     /// This method enumerates all the providers and if they are FDO enabled for

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -1065,6 +1065,74 @@
     return (MgBatchPropertyCollection*)cmd.GetReturnValue().val.m_obj;
 }
 
+/////////////////////////////////////////////////////////////////
+/// \brief
+/// The QueryFeatureProperties operation identifies those features that
+/// meet the specified spatial selection criteria. This operation
+/// is used to implement WMS feature info and returns property values
+/// for all features which match the spatial query
+///
+/// \param map
+/// Input
+/// map object containing current state of map.
+/// \param layerNames
+/// Input
+/// Active layer names for which to query features
+/// \param filterGeometry
+/// Input
+/// geometry object specifying the selection area
+/// \param selectionVariant
+/// Input
+/// selection criterion - integer value corresponding to one of
+/// the MgFeatureSpatialOperations values
+/// \param featureFilter
+/// Input
+/// an XML selection string containing the required feature IDs
+/// \param maxFeatures
+/// Input
+/// the maximum number of features to return
+/// \param layerAttributeFilter
+/// Input
+/// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+///
+/// \return
+/// An MgSelection instance identifying the features that meet the
+/// selection criteria. Returns null if no features are identified.
+///
+MgBatchPropertyCollection* MgProxyRenderingService::QueryFeatureProperties(
+    MgMap* map,
+    MgStringCollection* layerNames,
+    MgGeometry* filterGeometry,
+    INT32 selectionVariant,
+    CREFSTRING featureFilter,
+    INT32 maxFeatures,
+    INT32 layerAttributeFilter,
+    bool bIncludeFeatureBBOX,
+    bool bIncludeGeometry)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                      // Connection
+        MgCommand::knObject,                            // Return type expected
+        MgRenderingServiceOpId::QueryFeatureProperties3,// Command Code
+        9,                                              // No of arguments
+        Rendering_Service,                              // Service Id
+        BUILD_VERSION(3, 3, 0),                         // Operation version
+        MgCommand::knObject, map,                       // Argument#1
+        MgCommand::knObject, layerNames,                // Argument#2
+        MgCommand::knObject, filterGeometry,            // Argument#3
+        MgCommand::knInt32, selectionVariant,           // Argument#4
+        MgCommand::knString, &featureFilter,            // Argument#5
+        MgCommand::knInt32, maxFeatures,                // Argument#6
+        MgCommand::knInt32, layerAttributeFilter,       // Argument#7
+        MgCommand::knInt8, (INT8)bIncludeFeatureBBOX,   // Argument#8
+        MgCommand::knInt8, (INT8)bIncludeGeometry,      // Argument#9
+        MgCommand::knNone);                             // End of arguments
+
+    SetWarning(cmd.GetWarningObject());
+
+    return (MgBatchPropertyCollection*)cmd.GetReturnValue().val.m_obj;
+}
+
 //////////////////////////////////////////////////////////////////
 /// \brief
 /// Sets the connection properties for the Proxy Service.  This

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -954,6 +954,57 @@
         INT32 layerAttributeFilter,
         bool bIncludeFeatureBBOX);
 
+    /////////////////////////////////////////////////////////////////
+    /// \brief
+    /// The QueryFeatureProperties operation identifies those features that
+    /// meet the specified spatial selection criteria. This operation
+    /// is used to implement WMS feature info and returns property values
+    /// for all features which match the spatial query
+    ///
+    /// \param map
+    /// Input
+    /// map object containing current state of map.
+    /// \param layerNames
+    /// Input
+    /// Active layer names for which to query features
+    /// \param filterGeometry
+    /// Input
+    /// geometry object specifying the selection area
+    /// \param selectionVariant
+    /// Input
+    /// selection criterion - integer value corresponding to one of
+    /// the MgFeatureSpatialOperations values
+    /// \param featureFilter
+    /// Input
+    /// an XML selection string containing the required feature IDs
+    /// \param maxFeatures
+    /// Input
+    /// the maximum number of features to return
+    /// \param layerAttributeFilter
+    /// Input
+    /// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+    /// \param bIncludeFeatureBBOX
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
+    /// \param bIncludeGeometry
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
+    ///
+    /// \return
+    /// An MgSelection instance identifying the features that meet the
+    /// selection criteria. Returns null if no features are identified.
+    ///
+    virtual MgBatchPropertyCollection* QueryFeatureProperties(
+        MgMap* map,
+        MgStringCollection* layerNames,
+        MgGeometry* filterGeometry,
+        INT32 selectionVariant,
+        CREFSTRING featureFilter,
+        INT32 maxFeatures,
+        INT32 layerAttributeFilter,
+        bool bIncludeFeatureBBOX,
+        bool bIncludeGeometry);
+
 protected:
 
     //////////////////////////////////////////////////////////////////

Modified: trunk/MgDev/Common/MapGuideCommon/Services/RenderingDefs.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/RenderingDefs.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/MapGuideCommon/Services/RenderingDefs.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -46,6 +46,7 @@
     static const int RenderMap6                 = 0x1111E912;
     static const int RenderMap7                 = 0x1111E913;
     static const int RenderTileUTFGrid          = 0x1111E914;
+    static const int QueryFeatureProperties3    = 0x1111E915;
 };
 /// \endcond
 

Modified: trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -47,17 +47,4 @@
 void MgRenderingService::Dispose()
 {
     delete this;
-}
-
-MgBatchPropertyCollection* MgRenderingService::QueryFeatureProperties(
-    MgMap* map,
-    MgStringCollection* layerNames,
-    MgGeometry* filterGeometry,
-    INT32 selectionVariant,
-    CREFSTRING featureFilter,
-    INT32 maxFeatures,
-    INT32 layerAttributeFilter,
-    bool bIncludeFeatureBBOX)
-{
-    throw new MgNotImplementedException(L"MgRenderingService.QueryFeatureProperties", __LINE__, __WFILE__, NULL, L"", NULL);
 }
\ No newline at end of file

Modified: trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -948,6 +948,9 @@
     /// \param layerAttributeFilter
     /// Input
     /// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+    /// \param bIncludeFeatureBBOX
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
     ///
     /// \return
     /// An MgSelection instance identifying the features that meet the
@@ -961,8 +964,59 @@
         CREFSTRING featureFilter,
         INT32 maxFeatures,
         INT32 layerAttributeFilter,
-        bool bIncludeFeatureBBOX);
+        bool bIncludeFeatureBBOX) = 0;
 
+    /////////////////////////////////////////////////////////////////
+    /// \brief
+    /// The QueryFeatureProperties operation identifies those features that
+    /// meet the specified spatial selection criteria. This operation
+    /// is used to implement WMS feature info and returns property values
+    /// for all features which match the spatial query
+    ///
+    /// \param map
+    /// Input
+    /// map object containing current state of map.
+    /// \param layerNames
+    /// Input
+    /// Active layer names for which to query features
+    /// \param filterGeometry
+    /// Input
+    /// geometry object specifying the selection area
+    /// \param selectionVariant
+    /// Input
+    /// selection criterion - integer value corresponding to one of
+    /// the MgFeatureSpatialOperations values
+    /// \param featureFilter
+    /// Input
+    /// an XML selection string containing the required feature IDs
+    /// \param maxFeatures
+    /// Input
+    /// the maximum number of features to return
+    /// \param layerAttributeFilter
+    /// Input
+    /// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+    /// \param bIncludeFeatureBBOX
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
+    /// \param bIncludeGeometry
+    /// Input
+    /// Indicates whether a bounding box should be included. If true, bounding box is recorded as a special property named _MgFeatureBoundingBox
+    ///
+    /// \return
+    /// An MgSelection instance identifying the features that meet the
+    /// selection criteria. Returns null if no features are identified.
+    ///
+    virtual MgBatchPropertyCollection* QueryFeatureProperties(
+        MgMap* map,
+        MgStringCollection* layerNames,
+        MgGeometry* filterGeometry,
+        INT32 selectionVariant,
+        CREFSTRING featureFilter,
+        INT32 maxFeatures,
+        INT32 layerAttributeFilter,
+        bool bIncludeFeatureBBOX,
+        bool bIncludeGeometry) = 0;
+
 protected:
 
     /////////////////////////////////////////////////////////////////

Modified: trunk/MgDev/Common/PlatformBase/Services/FeatureDefs.h
===================================================================
--- trunk/MgDev/Common/PlatformBase/Services/FeatureDefs.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/PlatformBase/Services/FeatureDefs.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -83,6 +83,8 @@
     static const int UpdateMatchingFeatures = 0x1111ED33;
     static const int DeleteFeatures         = 0x1111ED34;
     static const int SelectFeaturesWithTransform = 0x1111ED35;
+
+    static const int GetWfsReader_Id = 0x1111ED36;
 };
 /// \endcond
 

Modified: trunk/MgDev/Common/PlatformBase/Services/FeatureService.h
===================================================================
--- trunk/MgDev/Common/PlatformBase/Services/FeatureService.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/PlatformBase/Services/FeatureService.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -2038,6 +2038,60 @@
                                         CREFSTRING namespacePrefix,
                                         CREFSTRING namespaceUrl) = 0;
 
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Retrieves feature information based on the supplied criteria.
+    ///
+    /// \note1
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgFeatureReader GetWfsReader(MgResourceIdentifier featureSourceId, string featureClass, MgStringCollection requiredProperties, string srs, string filter, int maxFeatures, string outputFormat, string sortCriteria);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgFeatureReader GetWfsReader(MgResourceIdentifier featureSourceId, string featureClass, MgStringCollection requiredProperties, string srs, string filter, int maxFeatures, string outputFormat, string sortCriteria);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgFeatureReader GetWfsReader(MgResourceIdentifier featureSourceId, string featureClass, MgStringCollection requiredProperties, string srs, string filter, int maxFeatures, string outputFormat, string sortCriteria);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param featureSourceId (MgResourceIdentifier)
+    /// The resource identifier defining the
+    /// location of the feature source in
+    /// the repository.
+    /// \param featureClass (String/string)
+    /// The feature class containing the features to retrieve.
+    /// \param requiredProperties (MgStringCollection)
+    /// The collection of properties to retrieve for each feature. If the
+    /// collection is null or empty, all properties will be retrieved.
+    /// \param srs (String/string)
+    /// The spatial reference system in which to return feature geometries
+    /// \param filter (String/string)
+    /// An XML string containing the definition for an OGC filter
+    /// \param sortCriteria (String/string)
+    /// A string identifying the sort criteria
+    ///
+    /// \remarks
+    /// The purpose of this method, as opposed to GetWfsFeature is to return the base reader using the same input parameters
+    /// allowing for the caller to determine the desired output format and the desired content transformations required from 
+    /// the reader.
+    ///
+    /// The main use case for this method is for providing the base feature reader for outputting WFS GetFeature responses in 
+    /// formats other than GML
+    ///
+    /// \return
+    /// Returns an MgByteReader containing the requested feature information.
+    ///
+    /// \exception MgInvalidArgumentException
+    ///
+    /// \since 3.3
+    virtual MgFeatureReader* GetWfsReader(MgResourceIdentifier* featureSourceId,
+                                          CREFSTRING featureClass,
+                                          MgStringCollection* requiredProperties,
+                                          CREFSTRING srs,
+                                          CREFSTRING filter,
+                                          CREFSTRING sortCriteria) = 0;
+
     ////////////////////////////////////////////////////////////////////////////////
     /// \brief
     /// This method enumerates all the providers and if they are FDO enabled for

Modified: trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.h
===================================================================
--- trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/PlatformBase/Services/GeoJsonWriter.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -195,6 +195,7 @@
 
 INTERNAL_API:
     STRING GeometryToGeoJson(MgGeometry* geom);
+    void ToGeoJson(MgGeometry* geom, REFSTRING str, bool bIncludePrefix = true);
 
 protected:
     virtual void Dispose();
@@ -202,7 +203,6 @@
 private:
     static STRING EscapeJsonString(CREFSTRING str);
     void ValueToString(MgReader* reader, INT32 index, REFSTRING str);
-    void ToGeoJson(MgGeometry* geom, REFSTRING str, bool bIncludePrefix = true);
     void CoordinateToGeoJson(MgCoordinate* coord, REFSTRING str);
     void CoordinatesToGeoJson(MgCoordinateIterator* coords, REFSTRING str);
     void PolygonToGeoJson(MgPolygon* poly, REFSTRING str);

Modified: trunk/MgDev/Common/Stylization/RendererStyles.h
===================================================================
--- trunk/MgDev/Common/Stylization/RendererStyles.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Common/Stylization/RendererStyles.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -728,12 +728,12 @@
 {
 public:
     RS_FeatureClassInfo() :
-        m_name(L""), m_source(L"")
+        m_name(L""), m_source(L""), m_geometry(L"")
     {
     }
 
-    RS_FeatureClassInfo(const RS_String& name, const RS_String& source) :
-        m_name(name), m_source(source)
+    RS_FeatureClassInfo(const RS_String& name, const RS_String& source, const RS_String& geometry) :
+        m_name(name), m_source(source), m_geometry(geometry)
     {
     }
 
@@ -751,10 +751,12 @@
     inline RS_String&              name()     { return m_name; }
     inline std::vector<RS_String>& mappings() { return m_propMappings; }
     inline RS_String&              source()   { return m_source; }
+    inline RS_String&              geometry() { return m_geometry; }
 
 private:
     RS_String m_source;
     RS_String m_name;
+    RS_String m_geometry;
     std::vector<RS_String> m_propMappings;
 };
 

Modified: trunk/MgDev/Server/src/Services/Feature/FeatureOperationFactory.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/FeatureOperationFactory.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Feature/FeatureOperationFactory.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -58,6 +58,7 @@
 #include "OpGetIdentityProperties.h"
 #include "OpDescribeWfsFeatureType.h"
 #include "OpGetWfsFeature.h"
+#include "OpGetWfsReader.h"
 #include "OpEnumerateDataStores.h"
 #include "OpGetSchemaMapping.h"
 #include "OpGetFdoCacheInfo.h"
@@ -579,6 +580,18 @@
         }
         break;
 
+    case MgFeatureServiceOpId::GetWfsReader_Id:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(3, 3):
+            handler.reset(new MgOpGetWfsReader());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgFeatureOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
+
     case MgFeatureServiceOpId::EnumerateDataStores_Id:
         switch (VERSION_NO_PHASE(operationVersion))
         {
@@ -677,11 +690,11 @@
         }
         break;
 
-	case MgFeatureServiceOpId::AddSavePoint_Id:
-		switch (VERSION_NO_PHASE(operationVersion))
+    case MgFeatureServiceOpId::AddSavePoint_Id:
+        switch (VERSION_NO_PHASE(operationVersion))
         {
         case VERSION_SUPPORTED(1,0):
-			handler.reset(new MgOpAddSavePoint());
+            handler.reset(new MgOpAddSavePoint());
             break;
         default:
             throw new MgInvalidOperationVersionException(
@@ -693,7 +706,7 @@
         switch (VERSION_NO_PHASE(operationVersion))
         {
         case VERSION_SUPPORTED(1,0):
-	        handler.reset(new MgOpRollbackSavePoint());
+            handler.reset(new MgOpRollbackSavePoint());
             break;
         default:
             throw new MgInvalidOperationVersionException(
@@ -702,7 +715,7 @@
         break;
 
     case MgFeatureServiceOpId::ReleaseSavePoint_Id:
-		switch (VERSION_NO_PHASE(operationVersion))
+        switch (VERSION_NO_PHASE(operationVersion))
         {
         case VERSION_SUPPORTED(1,0):
             handler.reset(new MgOpReleaseSavePoint());

Modified: trunk/MgDev/Server/src/Services/Feature/Makefile.am
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/Makefile.am	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Feature/Makefile.am	2017-11-26 22:22:40 UTC (rev 9256)
@@ -105,7 +105,9 @@
   ByteSourceRasterStreamImpl.cpp \
   OpDescribeWfsFeatureType.cpp \
   OpGetWfsFeature.cpp \
+  OpGetWfsReader.cpp \
   FilterUtil.cpp \
+  WfsQueryAdapter.cpp \
   OpEnumerateDataStores.cpp \
   OpGetSchemaMapping.cpp \
   ServerEnumerateDataStores.cpp \
@@ -216,7 +218,9 @@
   DateTimeDataReaderCreator.h \
   OpDescribeWfsFeatureType.h \
   OpGetWfsFeature.h \
+  OpGetWfsReader.h \
   FilterUtil.h \
+  WfsQueryAdapter.h \
   OpEnumerateDataStores.h \
   OpGetSchemaMapping.h \
   ServerEnumerateDataStores.h \

Copied: trunk/MgDev/Server/src/Services/Feature/OpGetWfsReader.cpp (from rev 9255, sandbox/jng/ogc/Server/src/Services/Feature/OpGetWfsReader.cpp)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpGetWfsReader.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpGetWfsReader.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -0,0 +1,140 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "ServerFeatureServiceDefs.h"
+#include "OpGetWfsFeature.h"
+#include "ServerFeatureService.h"
+#include "LogManager.h"
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Constructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpGetWfsReader::MgOpGetWfsReader()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Destructs the object.
+/// </summary>
+///----------------------------------------------------------------------------
+MgOpGetWfsReader::~MgOpGetWfsReader()
+{
+}
+
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Executes the operation.
+/// </summary>
+///
+/// <exceptions>
+/// MgException
+/// </exceptions>
+///----------------------------------------------------------------------------
+void MgOpGetWfsReader::Execute()
+{
+    ACE_DEBUG((LM_DEBUG, ACE_TEXT("  (%t) MgOpGetWfsReader::Execute()\n")));
+
+    MG_LOG_OPERATION_MESSAGE(L"GetWfsFeature");
+
+    MG_FEATURE_SERVICE_TRY()
+
+        MG_LOG_OPERATION_MESSAGE_INIT(m_packet.m_OperationVersion, m_packet.m_NumArguments);
+
+    ACE_ASSERT(m_stream != NULL);
+
+    if (6 == m_packet.m_NumArguments)
+    {
+        // Get the feature source
+        Ptr<MgResourceIdentifier> featureSourceId = (MgResourceIdentifier*)m_stream->GetObject();
+
+        // Get the schema name
+        STRING featureClass;
+        m_stream->GetString(featureClass);
+
+        // Get the required properties
+        Ptr<MgStringCollection> requiredProperties = (MgStringCollection*)m_stream->GetObject();
+
+        // Get the srs
+        STRING srs;
+        m_stream->GetString(srs);
+
+        // Get the filter
+        STRING filter;
+        m_stream->GetString(filter);
+
+        // Get the sort criteria
+        STRING sortCriteria;
+        m_stream->GetString(sortCriteria);
+
+        BeginExecution();
+
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(featureSourceId->ToString().c_str());
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(featureClass.c_str());
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(L"MgStringCollection");
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(srs.c_str());
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(filter.c_str());
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(sortCriteria.c_str());
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        // Execute the operation
+        Ptr<MgFeatureReader> fr = m_service->GetWfsReader(featureSourceId, featureClass, requiredProperties, srs, filter, sortCriteria);
+
+        // Write the response
+        EndExecution(fr);
+    }
+    else
+    {
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+    }
+
+    if (!m_argsRead)
+    {
+        throw new MgOperationProcessingException(L"MgOpGetWfsReader.Execute",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Successful operation
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
+
+    MG_FEATURE_SERVICE_CATCH(L"MgOpGetWfsReader.Execute")
+
+        if (mgException != NULL)
+        {
+            // Failed operation
+            MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Failure.c_str());
+        }
+
+    // Add access log entry for operation
+    MG_LOG_OPERATION_MESSAGE_ACCESS_ENTRY();
+
+    MG_FEATURE_SERVICE_THROW()
+}

Copied: trunk/MgDev/Server/src/Services/Feature/OpGetWfsReader.h (from rev 9255, sandbox/jng/ogc/Server/src/Services/Feature/OpGetWfsReader.h)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/OpGetWfsReader.h	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/OpGetWfsReader.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -0,0 +1,33 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef MG_OP_GET_WFS_READER_H
+#define MG_OP_GET_WFS_READER_H
+
+#include "FeatureOperation.h"
+
+class MgOpGetWfsReader : public MgFeatureOperation
+{
+public:
+    MgOpGetWfsReader();
+    virtual ~MgOpGetWfsReader();
+
+public:
+    virtual void Execute();
+};
+
+#endif

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -48,6 +48,7 @@
 #include "ServerSqlDataReader.h"
 #include "ServerFeatureTransaction.h"
 #include "TransformedGeometryFeatureReader.h"
+#include "WfsQueryAdapter.h"
 
 #include <Fdo/Xml/FeatureSerializer.h>
 #include <Fdo/Xml/FeatureWriter.h>
@@ -2043,7 +2044,29 @@
     return msds.GetIdentityProperties(resource, schemaName, classNames);
 }
 
+MgFeatureReader* MgServerFeatureService::GetWfsReader(MgResourceIdentifier* fs,
+                                                      CREFSTRING featureClass,
+                                                      MgStringCollection* propNames,
+                                                      CREFSTRING srs,
+                                                      CREFSTRING wfsFilter,
+                                                      CREFSTRING sortCriteria)
+{
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::GetWfsReader()");
 
+    Ptr<MgFeatureReader> mgfReader;
+
+    MG_FEATURE_SERVICE_TRY()
+
+    MgWfsQueryAdapter wfsQuery(this);
+    wfsQuery.SetOptions(fs, featureClass, propNames, srs, wfsFilter, sortCriteria);
+    mgfReader = wfsQuery.GetWfsReader();
+
+    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH_AND_THROW(fs, L"MgServerFeatureService.GetWfsReader")
+
+    return mgfReader.Detach();
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
 /// \brief
 /// Retrieves feature information based on the supplied criteria with specified format.
@@ -2110,163 +2133,19 @@
     MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::GetWfsFeature()");
 
     Ptr<MgByteReader> byteReader;
-    TransformCacheMap transformCache;
 
     MG_FEATURE_SERVICE_TRY()
 
-    STRING lfeatureName = featureClass;
-    STRING schemaName, className;
-    MgUtil::ParseQualifiedClassName(lfeatureName, schemaName, className);
+    MgWfsQueryAdapter wfsQuery(this);
+    wfsQuery.SetOptions(fs, featureClass, propNames, srs, wfsFilter, sortCriteria);
 
-    bool hashed = (0 == schemaName.find_first_of(
-        MG_SCHEMA_NAME_HASH_PREFIX.c_str(), 0, MG_SCHEMA_NAME_HASH_PREFIX.length()));
-    Ptr<MgStringCollection> classNames = new MgStringCollection();
+    Ptr<MgFeatureReader> mgfReader = wfsQuery.GetWfsReader();
+    Ptr<MgCoordinateSystemTransform> trans = wfsQuery.GetTransform();
+    Ptr<MgCoordinateSystem> mapCs = wfsQuery.GetMapCs();
+    Ptr<MgClassDefinition> fc = wfsQuery.GetClassDefinition();
 
-    if (!className.empty())
-    {
-        classNames->Add(className);
-    }
-
-    // Find the needed class definition.
-    Ptr<MgFeatureSchemaCollection> fsc = DescribeSchema(
-        fs, hashed ? L"" : schemaName, classNames);
-    Ptr<MgFeatureSchema> schema;
-    Ptr<MgClassDefinition> fc;
-    STRING schemaHash;
-
-    FindClassDefinition(fsc, schemaName, className, schemaHash, schema, fc);
-
-    if (hashed && NULL != schema.p)
-    {
-        MgUtil::FormatQualifiedClassName(schema->GetName(), className, lfeatureName);
-    }
-
-    MgCoordinateSystemFactory fact;
-    std::wstring wkt = srs;
-    if (wkt.empty())
-    {
-        //If there is no coordinate system pass in, get the default one in resource header.
-        MgServiceManager* serviceMan = MgServiceManager::GetInstance();
-        assert(NULL != serviceMan);
-        Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(serviceMan->RequestService(MgServiceType::ResourceService));
-        assert(resourceService != NULL);
-        Ptr<MgByteReader> byteReaderHeader = resourceService->GetResourceHeader(fs);
-        Ptr<MgByteSink> byteSinkHeader = new MgByteSink(byteReaderHeader);
-        std::string resourceHeader;
-        byteSinkHeader->ToStringUtf8(resourceHeader);
-        //parse for default SRS of this WFS, the format is:
-        //<Property xsi:noNamespaceSchemaLocation="Property-1.0.0.xsd">
-        //  <Name>_PrimarySRS</Name>
-        //  <Value>EPSG:4326</Value>
-        //</Property>
-        std::string primary("<Name>_PrimarySRS</Name>");
-        std::size_t primaryPos = resourceHeader.find(primary);
-        if (primaryPos != std::string::npos)
-        {
-            std::string begin("<Value>EPSG:");
-            std::size_t beginPos = resourceHeader.find(begin, primaryPos);
-            if (beginPos != std::string::npos)
-            {
-                std::size_t endPos = resourceHeader.find("</Value>", beginPos);
-                if (endPos != std::string::npos)
-                {
-                    std::string primarySRS = resourceHeader.substr(beginPos+begin.length(), endPos-beginPos-begin.length());
-                    int epsgCode = atoi(primarySRS.c_str());
-                    wkt = fact.ConvertEpsgCodeToWkt(epsgCode);
-                }
-            }
-        }
-    }
-
-    Ptr<MgCoordinateSystem> mapCs = NULL;
-    if (!wkt.empty())
-    {
-        MG_TRY();
-            mapCs = fact.Create(wkt);
-        MG_CATCH_AND_RELEASE();
-    }
-
-    //get a transform from feature space to mapping space
-    TransformCache* item = TransformCache::GetLayerToMapTransform(transformCache, lfeatureName, fs, mapCs, &fact, this, false);
-    Ptr<MgCoordinateSystemTransform> trans = item? item->GetMgTransform() : NULL;
     FdoPtr<MgGMLCsTransform> transform = new MgGMLCsTransform(trans);
 
-    assert(fc != NULL);
-    if (fc == NULL)
-        return NULL;
-
-    //execute the spatial query
-    Ptr<MgFeatureQueryOptions> options = new MgFeatureQueryOptions();
-
-    //add the properties we need from FDO
-    if (propNames)
-    {
-        for (int i=0; i<propNames->GetCount(); i++)
-            options->AddFeatureProperty(propNames->GetItem(i));
-    }
-
-    //convert the WFS filter to an FDO filter
-    //and set it to the FDO feature query
-    if (!wfsFilter.empty())
-    {
-        STRING GEOM_PROP_TAG = L"%MG_GEOM_PROP%"; //NOXLATE
-        STRING fdoFilterString = L""; //NOXLATE
-
-        Ptr<MgPropertyDefinitionCollection> properties = fc->GetProperties();
-        MgOgcFilterUtil u;
-        
-        for(int i = 0; i<properties->GetCount(); i++)
-        {
-            Ptr<MgPropertyDefinition> prop = properties->GetItem(i);
-            if(prop->GetPropertyType() == MgFeaturePropertyType::GeometricProperty)
-            {
-                STRING ogcFilter = wfsFilter;
-
-                if(wfsFilter.find(GEOM_PROP_TAG, 0) != STRING::npos)
-                {
-                    ogcFilter = MgUtil::ReplaceString(wfsFilter,GEOM_PROP_TAG.c_str(),prop->GetName().c_str());
-                }
-                if(!fdoFilterString.empty())
-                {
-                    fdoFilterString += L" OR "; //NOXLATE
-                }
-                TransformCache* itemFilter = TransformCache::GetLayerToMapTransform(transformCache, lfeatureName, fs, mapCs, &fact, this, true);
-                Ptr<MgCoordinateSystemTransform> transFilter = itemFilter? itemFilter->GetMgTransform() : NULL;
-                fdoFilterString += u.Ogc2FdoFilter(ogcFilter, transFilter, prop->GetName(), properties);
-            }
-        }
-
-        options->SetFilter(fdoFilterString);
-    }
-
-    if(!sortCriteria.empty())
-    {
-        Ptr<MgStringCollection> orderByProperties = new MgStringCollection();
-        int orderOption = MgOrderingOption::Ascending;
-
-        STRING sSortCriteria = sortCriteria;
-        STRING::size_type pos = sSortCriteria.find_last_of(L" ");
-        if(pos != STRING::npos)
-        {
-            STRING sSortByProperty = sSortCriteria.substr(0, pos);
-            orderByProperties->Add(sSortByProperty);
-
-            STRING sSortOption  = MgUtil::ToUpper(sSortCriteria.substr(pos+1));
-            if(sSortOption == L"D")
-            {
-                orderOption = MgOrderingOption::Descending;
-            }
-        }
-        else
-        {
-            orderByProperties->Add(sortCriteria);
-        }
-
-        options->SetOrderingFilter(orderByProperties,orderOption);
-    }
-    // TODO: can FeatureName be an extension name rather than a FeatureClass?
-    Ptr<MgFeatureReader> mgfReader = SelectFeatures(fs, lfeatureName, options);
-
     //get underlying FDO feature reader
     FdoPtr<FdoIFeatureReader> fdoReader = (NULL == mgfReader.p) ? NULL : ((MgServerFeatureReader*)(mgfReader.p))->GetInternalReader();
 
@@ -2394,12 +2273,8 @@
     src->SetMimeType(MgMimeType::Xml);
     byteReader = src->GetReader();
 
-    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH(fs, L"MgServerFeatureService.GetWfsFeature")
+    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH_AND_THROW(fs, L"MgServerFeatureService.GetWfsFeature")
 
-    TransformCache::Clear(transformCache);
-
-    MG_FEATURE_SERVICE_THROW()
-
     return byteReader.Detach();
 }
 

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.h
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -23,8 +23,12 @@
 
 #include <set>
 
+class MgWfsQueryAdapter;
+
 class MG_SERVER_FEATURE_API MgServerFeatureService : public MgFeatureService
 {
+    friend class MgWfsQueryAdapter;
+
     DECLARE_CLASSNAME(MgServerFeatureService)
 
 public:
@@ -941,6 +945,13 @@
                                 CREFSTRING filter,
                                 INT32 maxFeatures);
 
+    MgFeatureReader* GetWfsReader(MgResourceIdentifier* featureSourceId,
+                                  CREFSTRING featureClass,
+                                  MgStringCollection* requiredProperties,
+                                  CREFSTRING srs,
+                                  CREFSTRING filter,
+                                  CREFSTRING sortCriteria);
+
     ////////////////////////////////////////////////////////////////////////////////
     /// <summary>
     /// This method enumerates all the providers and if they are FDO enabled for

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj	2017-11-26 22:22:40 UTC (rev 9256)
@@ -415,6 +415,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="OpGetWfsReader.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="OpInsertFeatures.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -816,6 +822,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="WfsQueryAdapter.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="FdoForcedOneToOneFeatureReader.h" />
@@ -852,6 +864,7 @@
     <ClInclude Include="OpGetSpatialContexts.h" />
     <ClInclude Include="OpGetSqlRows.h" />
     <ClInclude Include="OpGetWfsFeature.h" />
+    <ClInclude Include="OpGetWfsReader.h" />
     <ClInclude Include="OpInsertFeatures.h" />
     <ClInclude Include="OpInsertFeaturesBatched.h" />
     <ClInclude Include="OpReleaseSavePoint.h" />
@@ -885,6 +898,7 @@
     <ClInclude Include="FeatureStringFunctions.h" />
     <ClInclude Include="FilterUtil.h" />
     <ClInclude Include="GeometryDataReaderCreator.h" />
+    <ClInclude Include="WfsQueryAdapter.h" />
     <CustomBuildStep Include="GwsConnectionPool.h">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2017-11-26 22:22:40 UTC (rev 9256)
@@ -201,6 +201,10 @@
       <Filter>Ops</Filter>
     </ClCompile>
     <ClCompile Include="TransformedGeometryFeatureReader.cpp" />
+    <ClCompile Include="OpGetWfsReader.cpp">
+      <Filter>Ops</Filter>
+    </ClCompile>
+    <ClCompile Include="WfsQueryAdapter.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="FeatureOperation.h">
@@ -411,6 +415,10 @@
       <Filter>Ops</Filter>
     </ClInclude>
     <ClInclude Include="TransformedGeometryFeatureReader.h" />
+    <ClInclude Include="OpGetWfsReader.h">
+      <Filter>Ops</Filter>
+    </ClInclude>
+    <ClInclude Include="WfsQueryAdapter.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ServerFeatureService.rc" />

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -86,7 +86,9 @@
 #include "OpGetIdentityProperties.cpp"
 #include "OpDescribeWfsFeatureType.cpp"
 #include "OpGetWfsFeature.cpp"
+#include "OpGetWfsReader.cpp"
 #include "FilterUtil.cpp"
+#include "WfsQueryAdapter.cpp"
 #include "ServerGwsFeatureReader.cpp"
 #include "GwsConnectionPool.cpp"
 #include "OpEnumerateDataStores.cpp"
@@ -111,4 +113,4 @@
 #include "OpInsertFeaturesBatched.cpp"
 #include "OpUpdateMatchingFeatures.cpp"
 #include "OpDeleteFeatures.cpp"
-#include "TransformedGeometryFeatureReader.cpp"
+#include "TransformedGeometryFeatureReader.cpp"
\ No newline at end of file

Copied: trunk/MgDev/Server/src/Services/Feature/WfsQueryAdapter.cpp (from rev 9255, sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.cpp)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/WfsQueryAdapter.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/WfsQueryAdapter.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -0,0 +1,216 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "ServerFeatureServiceDefs.h"
+#include "WfsQueryAdapter.h"
+
+MgWfsQueryAdapter::MgWfsQueryAdapter(MgServerFeatureService* featSvc)
+{
+    m_featSvc = SAFE_ADDREF(featSvc);
+}
+
+MgWfsQueryAdapter::~MgWfsQueryAdapter()
+{
+    TransformCache::Clear(m_transformCache);
+    m_classDef = NULL;
+    m_fs = NULL;
+    m_options = NULL;
+    m_featSvc = NULL;
+    m_mapCs = NULL;
+    m_xform = NULL;
+}
+
+bool MgWfsQueryAdapter::SetOptions(MgResourceIdentifier* fs,
+                                   CREFSTRING featureClass,
+                                   MgStringCollection* propNames,
+                                   CREFSTRING srs,
+                                   CREFSTRING wfsFilter,
+                                   CREFSTRING sortCriteria)
+{
+    m_fs = SAFE_ADDREF(fs);
+    m_className = featureClass;
+    STRING schemaName, className;
+    MgUtil::ParseQualifiedClassName(m_className, schemaName, className);
+
+    bool hashed = (0 == schemaName.find_first_of(MG_SCHEMA_NAME_HASH_PREFIX.c_str(), 0, MG_SCHEMA_NAME_HASH_PREFIX.length()));
+    Ptr<MgStringCollection> classNames = new MgStringCollection();
+
+    if (!className.empty())
+    {
+        classNames->Add(className);
+    }
+
+    // Find the needed class definition.
+    Ptr<MgFeatureSchemaCollection> fsc = m_featSvc->DescribeSchema(m_fs, hashed ? L"" : schemaName, classNames);
+    Ptr<MgFeatureSchema> schema;
+    STRING schemaHash;
+
+    m_featSvc->FindClassDefinition(fsc, schemaName, className, schemaHash, schema, m_classDef);
+
+    if (hashed && NULL != schema.p)
+    {
+        MgUtil::FormatQualifiedClassName(schema->GetName(), className, m_className);
+    }
+
+    MgCoordinateSystemFactory fact;
+    std::wstring wkt = srs;
+    if (wkt.empty())
+    {
+        //If there is no coordinate system pass in, get the default one in resource header.
+        MgServiceManager* serviceMan = MgServiceManager::GetInstance();
+        assert(NULL != serviceMan);
+        Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(serviceMan->RequestService(MgServiceType::ResourceService));
+        assert(resourceService != NULL);
+        Ptr<MgByteReader> byteReaderHeader = resourceService->GetResourceHeader(m_fs);
+        Ptr<MgByteSink> byteSinkHeader = new MgByteSink(byteReaderHeader);
+        std::string resourceHeader;
+        byteSinkHeader->ToStringUtf8(resourceHeader);
+        //parse for default SRS of this WFS, the format is:
+        //<Property xsi:noNamespaceSchemaLocation="Property-1.0.0.xsd">
+        //  <Name>_PrimarySRS</Name>
+        //  <Value>EPSG:4326</Value>
+        //</Property>
+        std::string primary("<Name>_PrimarySRS</Name>");
+        std::size_t primaryPos = resourceHeader.find(primary);
+        if (primaryPos != std::string::npos)
+        {
+            std::string begin("<Value>EPSG:");
+            std::size_t beginPos = resourceHeader.find(begin, primaryPos);
+            if (beginPos != std::string::npos)
+            {
+                std::size_t endPos = resourceHeader.find("</Value>", beginPos);
+                if (endPos != std::string::npos)
+                {
+                    std::string primarySRS = resourceHeader.substr(beginPos + begin.length(), endPos - beginPos - begin.length());
+                    int epsgCode = atoi(primarySRS.c_str());
+                    wkt = fact.ConvertEpsgCodeToWkt(epsgCode);
+                }
+            }
+        }
+    }
+
+    if (!wkt.empty())
+    {
+        MG_TRY();
+        m_mapCs = fact.Create(wkt);
+        MG_CATCH_AND_RELEASE();
+    }
+
+    //get a transform from feature space to mapping space
+    TransformCache* item = TransformCache::GetLayerToMapTransform(m_transformCache, m_className, m_fs, m_mapCs, &fact, m_featSvc, false);
+    m_xform = item ? item->GetMgTransform() : NULL;
+
+    assert(m_classDef.p != NULL);
+    if (NULL == m_classDef.p)
+        return false;
+
+    //execute the spatial query
+    Ptr<MgFeatureQueryOptions> options = new MgFeatureQueryOptions();
+
+    //add the properties we need from FDO
+    if (propNames)
+    {
+        for (int i = 0; i<propNames->GetCount(); i++)
+            options->AddFeatureProperty(propNames->GetItem(i));
+    }
+
+    //convert the WFS filter to an FDO filter
+    //and set it to the FDO feature query
+    if (!wfsFilter.empty())
+    {
+        STRING GEOM_PROP_TAG = L"%MG_GEOM_PROP%"; //NOXLATE
+        STRING fdoFilterString = L""; //NOXLATE
+
+        Ptr<MgPropertyDefinitionCollection> properties = m_classDef->GetProperties();
+        MgOgcFilterUtil u;
+
+        for (int i = 0; i<properties->GetCount(); i++)
+        {
+            Ptr<MgPropertyDefinition> prop = properties->GetItem(i);
+            if (prop->GetPropertyType() == MgFeaturePropertyType::GeometricProperty)
+            {
+                STRING ogcFilter = wfsFilter;
+
+                if (wfsFilter.find(GEOM_PROP_TAG, 0) != STRING::npos)
+                {
+                    ogcFilter = MgUtil::ReplaceString(wfsFilter, GEOM_PROP_TAG.c_str(), prop->GetName().c_str());
+                }
+                if (!fdoFilterString.empty())
+                {
+                    fdoFilterString += L" OR "; //NOXLATE
+                }
+                TransformCache* itemFilter = TransformCache::GetLayerToMapTransform(m_transformCache, m_className, m_fs, m_mapCs, &fact, m_featSvc, true);
+                Ptr<MgCoordinateSystemTransform> transFilter = itemFilter ? itemFilter->GetMgTransform() : NULL;
+                fdoFilterString += u.Ogc2FdoFilter(ogcFilter, transFilter, prop->GetName(), properties);
+            }
+        }
+
+        options->SetFilter(fdoFilterString);
+    }
+
+    if (!sortCriteria.empty())
+    {
+        Ptr<MgStringCollection> orderByProperties = new MgStringCollection();
+        int orderOption = MgOrderingOption::Ascending;
+
+        STRING sSortCriteria = sortCriteria;
+        STRING::size_type pos = sSortCriteria.find_last_of(L" ");
+        if (pos != STRING::npos)
+        {
+            STRING sSortByProperty = sSortCriteria.substr(0, pos);
+            orderByProperties->Add(sSortByProperty);
+
+            STRING sSortOption = MgUtil::ToUpper(sSortCriteria.substr(pos + 1));
+            if (sSortOption == L"D")
+            {
+                orderOption = MgOrderingOption::Descending;
+            }
+        }
+        else
+        {
+            orderByProperties->Add(sortCriteria);
+        }
+
+        options->SetOrderingFilter(orderByProperties, orderOption);
+    }
+    return true;
+}
+
+MgClassDefinition* MgWfsQueryAdapter::GetClassDefinition()
+{
+    return SAFE_ADDREF(m_classDef.p);
+}
+
+MgCoordinateSystemTransform* MgWfsQueryAdapter::GetTransform()
+{
+    return SAFE_ADDREF(m_xform.p);
+}
+
+MgCoordinateSystem* MgWfsQueryAdapter::GetMapCs()
+{
+    return SAFE_ADDREF(m_mapCs.p);
+}
+
+MgFeatureReader* MgWfsQueryAdapter::GetWfsReader()
+{
+    Ptr<MgFeatureReader> fr;
+    MG_FEATURE_SERVICE_TRY()
+    // TODO: can FeatureName be an extension name rather than a FeatureClass?
+    fr = m_featSvc->SelectFeatures(m_fs, m_className, m_options);
+    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH_AND_THROW(m_fs, L"MgWfsQueryAdapter.GetWfsReader")
+    return fr.Detach();
+}
\ No newline at end of file

Copied: trunk/MgDev/Server/src/Services/Feature/WfsQueryAdapter.h (from rev 9255, sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.h)
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/WfsQueryAdapter.h	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Feature/WfsQueryAdapter.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -0,0 +1,52 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef _MG_WFS_QUERY_ADAPTER_H_
+#define _MG_WFS_QUERY_ADAPTER_H_
+
+class MgServerFeatureService;
+
+// This is a helper class that contains most of the boilerplate for translating WFS GetFeature request parameters
+// to our feature service queries
+class MgWfsQueryAdapter 
+{
+public:
+    MgWfsQueryAdapter(MgServerFeatureService* featSvc);
+    ~MgWfsQueryAdapter();
+    bool SetOptions(MgResourceIdentifier* fs,
+                    CREFSTRING featureClass,
+                    MgStringCollection* propNames,
+                    CREFSTRING srs,
+                    CREFSTRING wfsFilter,
+                    CREFSTRING sortCriteria);
+    MgFeatureReader* GetWfsReader();
+    MgCoordinateSystem* GetMapCs();
+    MgCoordinateSystemTransform* GetTransform();
+    MgClassDefinition* GetClassDefinition();
+
+private:
+    Ptr<MgClassDefinition> m_classDef;
+    Ptr<MgResourceIdentifier> m_fs;
+    Ptr<MgFeatureQueryOptions> m_options;
+    Ptr<MgServerFeatureService> m_featSvc;
+    Ptr<MgCoordinateSystem> m_mapCs;
+    Ptr<MgCoordinateSystemTransform> m_xform;
+    STRING m_className;
+    TransformCacheMap m_transformCache;
+};
+
+#endif
\ No newline at end of file

Modified: trunk/MgDev/Server/src/Services/Kml/ServerKmlService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Kml/ServerKmlService.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Kml/ServerKmlService.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -480,7 +480,7 @@
 
         if (NULL != fdoReader.p)
         {
-            RS_FeatureClassInfo fcInfo(vl->GetFeatureName(), vl->GetResourceID());
+            RS_FeatureClassInfo fcInfo(vl->GetFeatureName(), vl->GetResourceID(), vl->GetGeometry());
             MdfModel::NameStringPairCollection* pmappings = vl->GetPropertyMappings();
             for (int j=0; j<pmappings->GetCount(); j++)
             {

Modified: trunk/MgDev/Server/src/Services/Mapping/MappingUtil.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/MappingUtil.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Mapping/MappingUtil.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -549,7 +549,7 @@
                     //string the viewer should be displaying as the name of each
                     //feature property
                     // TODO: check to see if name is FeatureClass or Extension name
-                    RS_FeatureClassInfo fcinfo(vl->GetFeatureName(), vl->GetResourceID());
+                    RS_FeatureClassInfo fcinfo(vl->GetFeatureName(), vl->GetResourceID(), vl->GetGeometry());
 
                     MdfModel::NameStringPairCollection* pmappings = vl->GetPropertyMappings();
                     for (int j=0; j<pmappings->GetCount(); j++)
@@ -661,7 +661,7 @@
                     //string the viewer should be displaying as the name of each
                     //feature property
                     // TODO: check to see if name is FeatureClass or Extension name
-                    RS_FeatureClassInfo fcinfo(gl->GetFeatureName(), gl->GetResourceID());
+                    RS_FeatureClassInfo fcinfo(gl->GetFeatureName(), gl->GetResourceID(), gl->GetGeometry());
 
                     //check for overridden feature query filter and remember it.
                     //we will use this when making feature queries


Property changes on: trunk/MgDev/Server/src/Services/Mapping/MappingUtil.cpp
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/2.4/MgDev/Server/src/Services/Mapping/MappingUtil.cpp:6738-6741,6749-6756,6777-6783,6785-6787,6789,6791-6794,6796-6801,6954-6962,6986-7006
/branches/2.6/MgDev/Server/src/Services/Mapping/MappingUtil.cpp:8365
/sandbox/adsk/2.4j/Server/src/Services/Mapping/MappingUtil.cpp:6327-6535
/sandbox/adsk/3.1n/Server/src/Services/Mapping/MappingUtil.cpp:8942
/sandbox/jng/clean_json/Server/src/Services/Mapping/MappingUtil.cpp:8818-9180
/sandbox/jng/createruntimemap/Server/src/Services/Mapping/MappingUtil.cpp:7486-7555
/sandbox/rfc94/Server/src/Services/Mapping/MappingUtil.cpp:5099-5163
   + /branches/2.4/MgDev/Server/src/Services/Mapping/MappingUtil.cpp:6738-6741,6749-6756,6777-6783,6785-6787,6789,6791-6794,6796-6801,6954-6962,6986-7006
/branches/2.6/MgDev/Server/src/Services/Mapping/MappingUtil.cpp:8365
/sandbox/adsk/2.4j/Server/src/Services/Mapping/MappingUtil.cpp:6327-6535
/sandbox/adsk/3.1n/Server/src/Services/Mapping/MappingUtil.cpp:8942
/sandbox/jng/clean_json/Server/src/Services/Mapping/MappingUtil.cpp:8818-9180
/sandbox/jng/createruntimemap/Server/src/Services/Mapping/MappingUtil.cpp:7486-7555
/sandbox/jng/ogc/Server/src/Services/Mapping/MappingUtil.cpp:9240-9255
/sandbox/rfc94/Server/src/Services/Mapping/MappingUtil.cpp:5099-5163

Modified: trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -24,9 +24,11 @@
 
 #define SPECIAL_PROP_LAYER_NAME     L"_MgLayerName"
 #define SPECIAL_PROP_BOUNDING_BOX   L"_MgFeatureBoundingBox"
+#define SPECIAL_PROP_GEOMETRY       L"_MgGeometry"
 
 FeaturePropRenderer::FeaturePropRenderer(MgSelection* selection, int maxFeatures, double mapScale, bool bIncludeFeatureBBOX)
-: FeatureInfoRenderer(selection, maxFeatures, mapScale)
+: FeatureInfoRenderer(selection, maxFeatures, mapScale),
+  m_bCaptureGeometry(false)
 {
     m_featprops = new MgBatchPropertyCollection();
     m_currentFeature = NULL;
@@ -93,6 +95,47 @@
         featureProps->Add(boundingBoxProperty);
     }
 
+    //Add geometry if we're instructed to capture it
+    if (m_bCaptureGeometry)
+    {
+        FdoPtr<FdoIFeatureReader> fr = feature->GetInternalReader();
+        const FdoString* geomName = m_fcInfo->geometry().c_str();
+        Ptr<MgGeometryProperty> geomProp = new MgGeometryProperty();
+        //Not using geometry prop name here as we want to specially denote the designated geometry value
+        geomProp->SetName(SPECIAL_PROP_GEOMETRY);
+        try
+        {
+            if (!fr->IsNull(geomName))
+            {
+                FdoInt32 len = 0;
+                const FdoByte* data = fr->GetGeometry(geomName, &len);
+
+                if (data != NULL)
+                {
+                    Ptr<MgByte> mgBytes = new MgByte((BYTE_ARRAY_IN)data, len);
+                    Ptr<MgByteSource> bSource = new MgByteSource(mgBytes);
+                    bSource->SetMimeType(MgMimeType::Agf);
+                    Ptr<MgByteReader> agf = bSource->GetReader();
+                    geomProp->SetValue(agf);
+                }
+                else
+                {
+                    geomProp->SetNull(true);
+                }
+            }
+            else
+            {
+                geomProp->SetNull(true);
+            }
+        }
+        catch (FdoException* ex)
+        {
+            FDO_SAFE_RELEASE(ex);
+        }
+
+        featureProps->Add(geomProp);
+    }
+
     //for each property in the property mapping, add to the
     //return property collection
 
@@ -175,6 +218,11 @@
     bbox->SetValue(val);
 }
 
+void FeaturePropRenderer::SetGeometryCapture(bool bCaptureGeometry) 
+{
+    m_bCaptureGeometry = bCaptureGeometry;
+}
+
 void FeaturePropRenderer::ProcessPolygon(LineBuffer*   lb,
                                          RS_FillStyle& fill)
 {

Modified: trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.h
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -74,6 +74,8 @@
     void GetGeometryBounds(const LineBuffer* lb, RS_Bounds& bounds);
     void SetBBOXProperty(const RS_Bounds& bounds, MgStringProperty* bbox);
 
+    void SetGeometryCapture(bool bCaptureGeometry);
+
     MgBatchPropertyCollection* GetProperties()
     {
         return SAFE_ADDREF(m_featprops);
@@ -83,6 +85,7 @@
     MgBatchPropertyCollection* m_featprops;
     MgPropertyCollection* m_currentFeature;
     bool m_bIncludeFeatureBBOX;
+    bool m_bCaptureGeometry;
 };
 
 #endif

Modified: trunk/MgDev/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -60,7 +60,7 @@
 
     ACE_ASSERT(m_stream != NULL);
 
-    if (7 == m_packet.m_NumArguments || 8 == m_packet.m_NumArguments)
+    if (7 == m_packet.m_NumArguments || 8 == m_packet.m_NumArguments || 9 == m_packet.m_NumArguments)
     {
         Ptr<MgMap> map = (MgMap*)m_stream->GetObject();
         Ptr<MgResourceIdentifier> resource = map->GetResourceId();
@@ -82,10 +82,15 @@
         m_stream->GetInt32(layerAttributeFilter);
 
         bool bIncludeFeatureBBOX = false;
-        if (8 == m_packet.m_NumArguments)
+        if (8 <= m_packet.m_NumArguments)
         {
             m_stream->GetBoolean(bIncludeFeatureBBOX);
         }
+        bool bIncludeGeometry = false;
+        if (9 == m_packet.m_NumArguments)
+        {
+            m_stream->GetBoolean(bIncludeGeometry);
+        }
         BeginExecution();
 
         MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
@@ -102,19 +107,29 @@
         MG_LOG_OPERATION_MESSAGE_ADD_INT32(maxFeatures);
         MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
         MG_LOG_OPERATION_MESSAGE_ADD_INT32(layerAttributeFilter);
-        if (8 == m_packet.m_NumArguments)
+        if (8 <= m_packet.m_NumArguments)
         {
             MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
             MG_LOG_OPERATION_MESSAGE_ADD_BOOL(bIncludeFeatureBBOX);
         }
+        if (9 == m_packet.m_NumArguments)
+        {
+            MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+            MG_LOG_OPERATION_MESSAGE_ADD_BOOL(bIncludeGeometry);
+        }
         MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
 
         Validate();
 
         Ptr<MgBatchPropertyCollection> info;
-        if (8 == m_packet.m_NumArguments)
+        if (9 == m_packet.m_NumArguments)
         {
             info = m_service->QueryFeatureProperties(map, layerNames, geom, selectionVariant,
+                featureFilter, maxFeatures, layerAttributeFilter, bIncludeFeatureBBOX, bIncludeGeometry);
+        }
+        else if (8 == m_packet.m_NumArguments)
+        {
+            info = m_service->QueryFeatureProperties(map, layerNames, geom, selectionVariant,
                 featureFilter, maxFeatures, layerAttributeFilter, bIncludeFeatureBBOX);
         }
         else

Modified: trunk/MgDev/Server/src/Services/Rendering/RenderingOperationFactory.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/RenderingOperationFactory.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Rendering/RenderingOperationFactory.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -260,6 +260,17 @@
                 L"MgRenderingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
         }
         break;
+    case MgRenderingServiceOpId::QueryFeatureProperties3:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(3, 3):
+            handler.reset(new MgOpQueryFeatureProperties());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgRenderingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
     case MgRenderingServiceOpId::RenderMapLegend:
         switch (VERSION_NO_PHASE(operationVersion))
         {

Modified: trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -1328,6 +1328,20 @@
                                                                             INT32 layerAttributeFilter,
                                                                             bool bIncludeFeatureBBOX)
 {
+    return QueryFeatureProperties(map, layerNames, filterGeometry, selectionVariant, L"", maxFeatures, layerAttributeFilter, bIncludeFeatureBBOX, false);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+MgBatchPropertyCollection* MgServerRenderingService::QueryFeatureProperties(MgMap* map,
+                                                                            MgStringCollection* layerNames,
+                                                                            MgGeometry* filterGeometry,
+                                                                            INT32 selectionVariant, // Within, Touching, Topmost
+                                                                            CREFSTRING featureFilter,
+                                                                            INT32 maxFeatures,
+                                                                            INT32 layerAttributeFilter,
+                                                                            bool bIncludeFeatureBBOX,
+                                                                            bool bIncludeGeometry)
+{
     Ptr<MgBatchPropertyCollection> ret;
 
     MG_TRY()
@@ -1339,6 +1353,8 @@
     Ptr<MgSelection> sel;   //TODO: do we need this for this API? new MgSelection(map);
     FeaturePropRenderer fpr(sel, maxFeatures, map->GetViewScale(), bIncludeFeatureBBOX);
 
+    fpr.SetGeometryCapture(bIncludeGeometry);
+
     RenderForSelection(map, layerNames, filterGeometry, selectionVariant, featureFilter, maxFeatures, layerAttributeFilter, &fpr);
 
     ret = fpr.GetProperties();
@@ -1901,7 +1917,7 @@
                     //string the viewer should be displaying as the name of each
                     //feature property
                     // TODO: can FeatureName be an extension name rather than a FeatureClass?
-                    RS_FeatureClassInfo fcinfo(vl->GetFeatureName(), vl->GetResourceID());
+                    RS_FeatureClassInfo fcinfo(vl->GetFeatureName(), vl->GetResourceID(), vl->GetGeometry());
 
                     MdfModel::NameStringPairCollection* pmappings = vl->GetPropertyMappings();
                     for (int i=0; i<pmappings->GetCount(); i++)

Modified: trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.h
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -232,6 +232,17 @@
                                         INT32 layerAttributeFilter,
                                         bool bIncludeFeatureBBOX);
 
+    virtual MgBatchPropertyCollection* QueryFeatureProperties(
+                                        MgMap* map,
+                                        MgStringCollection* layerNames,
+                                        MgGeometry* filterGeometry,
+                                        INT32 selectionVariant,
+                                        CREFSTRING featureFilter,
+                                        INT32 maxFeatures,
+                                        INT32 layerAttributeFilter,
+                                        bool bIncludeFeatureBBOX,
+                                        bool bIncludeGeometry);
+
 private:
     static void ComputeXYZTileExtents(MgMap* map, INT32 x, INT32 y, INT32 z, RS_Bounds& extent);
     // used for tile generation

Modified: trunk/MgDev/Server/src/Wfs/OgcWfsService.config.awd
===================================================================
--- trunk/MgDev/Server/src/Wfs/OgcWfsService.config.awd	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Wfs/OgcWfsService.config.awd	2017-11-26 22:22:40 UTC (rev 9256)
@@ -158,6 +158,7 @@
    <item>text/xml; subtype=gml/2.1.2</item>
    <item>GML3</item>
    <item>text/xml; subtype=gml/3.1.1</item>
+   <item>application/json</item>
  </Define>
 
  <Define item="Formats.GetFeature.default.1.0.0">text/xml; subtype=gml/2.1.2</Define>

Modified: trunk/MgDev/Server/src/Wms/1.0.0.xml.awd
===================================================================
--- trunk/MgDev/Server/src/Wms/1.0.0.xml.awd	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Wms/1.0.0.xml.awd	2017-11-26 22:22:40 UTC (rev 9256)
@@ -75,6 +75,7 @@
   <FeatureInfo>
   <?Endif?>
   <?EnumFeatureProperties using="&FeatureProperty.xml;" ?>
+  <?EnumFeatureGeometries using="&FeatureGeometry.xml;" ?>
   </FeatureInfo>
  </Define>
 
@@ -83,6 +84,7 @@
    <td>
     <table>
      <?EnumFeatureProperties using="&FeatureProperty.html;" ?>
+     <?EnumFeatureGeometries using="&FeatureGeometry.html;" ?>
     </table>
    </td>
   </tr>
@@ -91,9 +93,16 @@
  <Define item="FeatureInfo.text">
   FeatureInfo:
   <?EnumFeatureProperties using="&FeatureProperty.text;" ?>
+  <?EnumFeatureGeometries using="&FeatureGeometry.text;" ?>
 
  </Define>
 
+ <Define item="FeatureInfo.json">{
+    "type": "Feature",
+    "properties": {<?EnumFeatureProperties using="&FeatureProperty.json;" ?>}
+    <?EnumFeatureGeometries using="&FeatureGeometry.json;" ?>
+}<?If l="&FeatureInfo.IsLast" op="eq" r="0"?>,<?Endif?></Define>
+
  <Define item="FeatureProperty.xml">
   <Property name="&FeatureProperty.Name;" value="&FeatureProperty.Value;"></Property>
  </Define>
@@ -117,7 +126,25 @@
  <Define item="Layer.Title">(Untitled Layer)</Define>
  <Define item="Layer.Abstract"></Define>
  <Define item="Layer.Name"></Define>
+ <!-- Output all non-geometry properties -->
+ <Define item="FeatureProperty.json">"&FeatureProperty.Name;": "&FeatureProperty.Value;"<?If l="&FeatureProperty.IsLast" op="eq" r="0"?>,<?Endif?></Define>
 
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.json">,"geometry": &FeatureGeometry.Value;</Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.text">Geometry=&FeatureGeometry.Value;</Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.html">
+  <tr><td class="name">Geometry</td><td>&FeatureGeometry.Value;</td></tr>
+ </Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.xml">
+  <Property name="Geometry" value="&FeatureGeometry.Value;"></Property>
+ </Define>
+
  <!-- We're currently not supporting child layers... -->
  <Define item="Layer.Sublayers"></Define>
 
@@ -355,9 +382,10 @@
 <html>
 <head>
 <title>GetFeatureInfo</title>
+&html.stylesheet;
 </head>
 <body>
-<table border="1">
+<table>
  <?EnumFeatureInfo using="&FeatureInfo.html;" ?>
 </table>
 </body>
@@ -374,7 +402,16 @@
  <?EnumFeatureInfo using="&FeatureInfo.text;" ?>
 </Response>
 
+<!-- 
 
+  WMS GetFeatureInfo - (Geo)JSON
+
+-->
+<Response request="GetFeatureInfo" content-type="application/json">{
+  "type": "FeatureCollection",
+  "features": [<?EnumFeatureInfo using="&FeatureInfo.json;" ?>]
+}</Response>
+
 <!--
 
   Exception format - XML

Modified: trunk/MgDev/Server/src/Wms/1.1.0.xml.awd
===================================================================
--- trunk/MgDev/Server/src/Wms/1.1.0.xml.awd	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Wms/1.1.0.xml.awd	2017-11-26 22:22:40 UTC (rev 9256)
@@ -77,6 +77,7 @@
   <FeatureInfo>
   <?Endif?>
   <?EnumFeatureProperties using="&FeatureProperty.xml;" ?>
+  <?EnumFeatureGeometries using="&FeatureGeometry.xml;" ?>
   </FeatureInfo>
  </Define>
 
@@ -85,6 +86,7 @@
    <td>
     <table>
      <?EnumFeatureProperties using="&FeatureProperty.html;" ?>
+     <?EnumFeatureGeometries using="&FeatureGeometry.html;" ?>
     </table>
    </td>
   </tr>
@@ -93,9 +95,16 @@
  <Define item="FeatureInfo.text">
   FeatureInfo:
   <?EnumFeatureProperties using="&FeatureProperty.text;" ?>
+  <?EnumFeatureGeometries using="&FeatureGeometry.text;" ?>
 
  </Define>
 
+ <Define item="FeatureInfo.json">{
+    "type": "Feature",
+    "properties": {<?EnumFeatureProperties using="&FeatureProperty.json;" ?>}
+    <?EnumFeatureGeometries using="&FeatureGeometry.json;" ?>
+}<?If l="&FeatureInfo.IsLast" op="eq" r="0"?>,<?Endif?></Define>
+
  <Define item="FeatureProperty.xml">
   <Property name="&FeatureProperty.Name;" value="&FeatureProperty.Value;"></Property>
  </Define>
@@ -123,6 +132,25 @@
   <item>EPSG:4326</item>
  </Define>
 
+ <!-- Output all non-geometry properties -->
+ <Define item="FeatureProperty.json">"&FeatureProperty.Name;": "&FeatureProperty.Value;"<?If l="&FeatureProperty.IsLast" op="eq" r="0"?>,<?Endif?></Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.json">,"geometry": &FeatureGeometry.Value;</Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.text">Geometry=&FeatureGeometry.Value;</Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.html">
+  <tr><td class="name">Geometry</td><td>&FeatureGeometry.Value;</td></tr>
+ </Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.xml">
+  <Property name="Geometry" value="&FeatureGeometry.Value;"></Property>
+ </Define>
+
  <!-- We're currently not supporting child layers... -->
  <Define item="Layer.Sublayers"></Define>
 
@@ -398,8 +426,17 @@
  <?EnumFeatureInfo using="&FeatureInfo.text;" ?>
 </Response>
 
+<!-- 
 
+  WMS GetFeatureInfo - (Geo)JSON
 
+-->
+<Response request="GetFeatureInfo" content-type="application/json">{
+  "type": "FeatureCollection",
+  "features": [<?EnumFeatureInfo using="&FeatureInfo.json;" ?>]
+}</Response>
+
+
 <!--
 
   Exception Format  - XML

Modified: trunk/MgDev/Server/src/Wms/1.1.1.xml.awd
===================================================================
--- trunk/MgDev/Server/src/Wms/1.1.1.xml.awd	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Wms/1.1.1.xml.awd	2017-11-26 22:22:40 UTC (rev 9256)
@@ -78,6 +78,7 @@
   <FeatureInfo>
   <?Endif?>
   <?EnumFeatureProperties using="&FeatureProperty.xml;" ?>
+  <?EnumFeatureGeometries using="&FeatureGeometry.xml;" ?>
   </FeatureInfo>
  </Define>
 
@@ -86,6 +87,7 @@
    <td>
     <table>
      <?EnumFeatureProperties using="&FeatureProperty.html;" ?>
+     <?EnumFeatureGeometries using="&FeatureGeometry.html;" ?>
     </table>
    </td>
   </tr>
@@ -94,9 +96,16 @@
  <Define item="FeatureInfo.text">
   FeatureInfo:
   <?EnumFeatureProperties using="&FeatureProperty.text;" ?>
+  <?EnumFeatureGeometries using="&FeatureGeometry.text;" ?>
 
  </Define>
 
+ <Define item="FeatureInfo.json">{
+    "type": "Feature",
+    "properties": {<?EnumFeatureProperties using="&FeatureProperty.json;" ?>}
+    <?EnumFeatureGeometries using="&FeatureGeometry.json;" ?>
+}<?If l="&FeatureInfo.IsLast" op="eq" r="0"?>,<?Endif?></Define>
+
  <Define item="FeatureProperty.xml">
   <Property name="&FeatureProperty.Name;" value="&FeatureProperty.Value;"></Property>
  </Define>
@@ -109,6 +118,25 @@
   &FeatureProperty.Name;=&FeatureProperty.Value;
  </Define>
 
+ <!-- Output all non-geometry properties -->
+ <Define item="FeatureProperty.json">"&FeatureProperty.Name;": "&FeatureProperty.Value;"<?If l="&FeatureProperty.IsLast" op="eq" r="0"?>,<?Endif?></Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.json">,"geometry": &FeatureGeometry.Value;</Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.text">Geometry=&FeatureGeometry.Value;</Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.html">
+  <tr><td class="name">Geometry</td><td>&FeatureGeometry.Value;</td></tr>
+ </Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.xml">
+  <Property name="Geometry" value="&FeatureGeometry.Value;"></Property>
+ </Define>
+
  <!-- We're currently not supporting child layers... -->
  <Define item="Layer.Sublayers"></Define>
 
@@ -358,9 +386,10 @@
 <html>
 <head>
 <title>GetFeatureInfo</title>
+&html.stylesheet;
 </head>
 <body>
-<table border="1">
+<table>
  <?EnumFeatureInfo using="&FeatureInfo.html;" ?>
 </table>
 </body>
@@ -377,7 +406,17 @@
  <?EnumFeatureInfo using="&FeatureInfo.text;" ?>
 </Response>
 
+<!-- 
 
+  WMS GetFeatureInfo - (Geo)JSON
+
+-->
+<Response request="GetFeatureInfo" content-type="application/json">{
+  "type": "FeatureCollection",
+  "features": [<?EnumFeatureInfo using="&FeatureInfo.json;" ?>]
+}</Response>
+
+
 <!--
 
   Exception format - XML

Modified: trunk/MgDev/Server/src/Wms/1.3.0.xml.awd
===================================================================
--- trunk/MgDev/Server/src/Wms/1.3.0.xml.awd	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Wms/1.3.0.xml.awd	2017-11-26 22:22:40 UTC (rev 9256)
@@ -88,6 +88,7 @@
   <FeatureInfo>
   <?Endif?>
   <?EnumFeatureProperties using="&FeatureProperty.xml;" ?>
+  <?EnumFeatureGeometries using="&FeatureGeometry.xml;" ?>
   </FeatureInfo>
  </Define>
 
@@ -96,6 +97,7 @@
    <td>
     <table>
      <?EnumFeatureProperties using="&FeatureProperty.html;" ?>
+     <?EnumFeatureGeometries using="&FeatureGeometry.html;" ?>
     </table>
    </td>
   </tr>
@@ -104,9 +106,16 @@
  <Define item="FeatureInfo.text">
   FeatureInfo:
   <?EnumFeatureProperties using="&FeatureProperty.text;" ?>
+  <?EnumFeatureGeometries using="&FeatureGeometry.text;" ?>
 
  </Define>
 
+ <Define item="FeatureInfo.json">{
+    "type": "Feature",
+    "properties": {<?EnumFeatureProperties using="&FeatureProperty.json;" ?>}
+    <?EnumFeatureGeometries using="&FeatureGeometry.json;" ?>
+}<?If l="&FeatureInfo.IsLast" op="eq" r="0"?>,<?Endif?></Define>
+
  <Define item="FeatureProperty.xml">
   <Property name="&FeatureProperty.Name;" value="&FeatureProperty.Value;"></Property>
  </Define>
@@ -119,6 +128,25 @@
   &FeatureProperty.Name;=&FeatureProperty.Value;
  </Define>
 
+ <!-- Output all non-geometry properties -->
+ <Define item="FeatureProperty.json">"&FeatureProperty.Name;": "&FeatureProperty.Value;"<?If l="&FeatureProperty.IsLast" op="eq" r="0"?>,<?Endif?></Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.json">,"geometry": &FeatureGeometry.Value;</Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.text">Geometry=&FeatureGeometry.Value;</Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.html">
+  <tr><td class="name">Geometry</td><td>&FeatureGeometry.Value;</td></tr>
+ </Define>
+
+ <!-- Only output if property name is the designated geometry -->
+ <Define item="FeatureGeometry.xml">
+  <Property name="Geometry" value="&FeatureGeometry.Value;"></Property>
+ </Define>
+
  <!-- We're currently not supporting child layers... -->
  <Define item="Layer.Sublayers"></Define>
 
@@ -365,9 +393,10 @@
 <html>
 <head>
 <title>GetFeatureInfo</title>
+&html.stylesheet;
 </head>
 <body>
-<table border="1">
+<table>
  <?EnumFeatureInfo using="&FeatureInfo.html;" ?>
 </table>
 </body>
@@ -384,7 +413,17 @@
  <?EnumFeatureInfo using="&FeatureInfo.text;" ?>
 </Response>
 
+<!-- 
 
+  WMS GetFeatureInfo - (Geo)JSON
+
+-->
+<Response request="GetFeatureInfo" content-type="application/json">{
+  "type": "FeatureCollection",
+  "features": [<?EnumFeatureInfo using="&FeatureInfo.json;" ?>]
+}</Response>
+
+
 <!--
 
   Exception format - XML

Modified: trunk/MgDev/Server/src/Wms/OgcWmsService.config.awd
===================================================================
--- trunk/MgDev/Server/src/Wms/OgcWmsService.config.awd	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Server/src/Wms/OgcWmsService.config.awd	2017-11-26 22:22:40 UTC (rev 9256)
@@ -180,6 +180,7 @@
    <item>text/xml</item>
    <item>text/html</item>
    <item>text/plain</item>
+   <item>application/json</item>
  </Define>
 
  <!-- These are the supported Exception formats

Modified: trunk/MgDev/UnitTest/TestData/Wfs/WfsTest.dump
===================================================================
--- trunk/MgDev/UnitTest/TestData/Wfs/WfsTest.dump	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/UnitTest/TestData/Wfs/WfsTest.dump	2017-11-26 22:22:40 UTC (rev 9256)
@@ -239,6 +239,7 @@
         <ows:Parameter>
           <ows:Value>GML2</ows:Value>
           <ows:Value>GML3</ows:Value>
+          <ows:Value>application/json</ows:Value>
           <ows:Value>text/xml; subtype=gml/2.1.2</ows:Value>
           <ows:Value>text/xml; subtype=gml/3.1.1</ows:Value>
         </ows:Parameter>
@@ -330,6 +331,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -350,6 +352,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -370,6 +373,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -388,6 +392,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -406,6 +411,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -424,6 +430,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -440,6 +447,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -456,6 +464,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -522,6 +531,7 @@
         <ows:Parameter>
           <ows:Value>GML2</ows:Value>
           <ows:Value>GML3</ows:Value>
+          <ows:Value>application/json</ows:Value>
           <ows:Value>text/xml; subtype=gml/2.1.2</ows:Value>
           <ows:Value>text/xml; subtype=gml/3.1.1</ows:Value>
         </ows:Parameter>
@@ -613,6 +623,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -633,6 +644,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -653,6 +665,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -671,6 +684,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -689,6 +703,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -707,6 +722,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -723,6 +739,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -739,6 +756,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -805,6 +823,7 @@
         <ows:Parameter>
           <ows:Value>GML2</ows:Value>
           <ows:Value>GML3</ows:Value>
+          <ows:Value>application/json</ows:Value>
           <ows:Value>text/xml; subtype=gml/2.1.2</ows:Value>
           <ows:Value>text/xml; subtype=gml/3.1.1</ows:Value>
         </ows:Parameter>
@@ -896,6 +915,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -916,6 +936,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -936,6 +957,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -954,6 +976,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -972,6 +995,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -990,6 +1014,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1006,6 +1031,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1022,6 +1048,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1088,6 +1115,7 @@
         <ows:Parameter>
           <ows:Value>GML2</ows:Value>
           <ows:Value>GML3</ows:Value>
+          <ows:Value>application/json</ows:Value>
           <ows:Value>text/xml; subtype=gml/2.1.2</ows:Value>
           <ows:Value>text/xml; subtype=gml/3.1.1</ows:Value>
         </ows:Parameter>
@@ -1179,6 +1207,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1199,6 +1228,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1219,6 +1249,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1237,6 +1268,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1255,6 +1287,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1273,6 +1306,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1289,6 +1323,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1305,6 +1340,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1371,6 +1407,7 @@
         <ows:Parameter>
           <ows:Value>GML2</ows:Value>
           <ows:Value>GML3</ows:Value>
+          <ows:Value>application/json</ows:Value>
           <ows:Value>text/xml; subtype=gml/2.1.2</ows:Value>
           <ows:Value>text/xml; subtype=gml/3.1.1</ows:Value>
         </ows:Parameter>
@@ -1462,6 +1499,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1482,6 +1520,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1502,6 +1541,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1520,6 +1560,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1538,6 +1579,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1556,6 +1598,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1572,6 +1615,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>
@@ -1588,6 +1632,7 @@
         <wfs:OutputFormats>
           <Format>GML2</Format>
           <Format>GML3</Format>
+          <Format>application/json</Format>
           <Format>text/xml; subtype=gml/2.1.2</Format>
           <Format>text/xml; subtype=gml/3.1.1</Format>
         </wfs:OutputFormats>

Modified: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/getfeatureinfowmsform.html
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/getfeatureinfowmsform.html	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/getfeatureinfowmsform.html	2017-11-26 22:22:40 UTC (rev 9256)
@@ -21,7 +21,7 @@
 <p> Info Format:
 <select name="INFO_FORMAT">
 <option value="text/xml">text/xml</option>
-<option value="itext/html">text/html</option>
+<option value="text/html">text/html</option>
 <option value="text/plain">text/plain</option>
 </select>
 <p> Map Layers (comma-separated):

Modified: trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/getfeaturewfsform.html
===================================================================
--- trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/getfeaturewfsform.html	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/UnitTest/WebTier/MapAgent/MapAgentForms/getfeaturewfsform.html	2017-11-26 22:22:40 UTC (rev 9256)
@@ -30,6 +30,7 @@
 <select name="OUTPUTFORMAT">
 <option value="GML3">GML3</option>
 <option value="GML2">GML2</option>
+<option value="application/json">application/json</option>
 </select>
 <p>
 <input type="submit" value="Submit" onclick="SetActionTarget()"> <input type="reset">

Modified: trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj	2017-11-26 22:22:40 UTC (rev 9256)
@@ -790,6 +790,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="WmsFeatureGeometry.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="WmsFeatureInfo.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -1108,6 +1114,7 @@
     <ClInclude Include="WfsFeatureDefinitions.h" />
     <ClInclude Include="WfsGetFeatureParams.h" />
     <ClInclude Include="WmsFeatureInfo.h" />
+    <ClInclude Include="WmsFeatureGeometry.h" />
     <ClInclude Include="WmsFeatureProperties.h" />
     <ClInclude Include="WmsLayerDefinitions.h" />
     <ClInclude Include="WmsMapUtil.h" />

Modified: trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj.filters
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj.filters	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/HttpHandler.vcxproj.filters	2017-11-26 22:22:40 UTC (rev 9256)
@@ -416,6 +416,9 @@
     <ClCompile Include="HttpGeoBoundary.cpp">
       <Filter>GeoProcessing</Filter>
     </ClCompile>
+    <ClCompile Include="WmsFeatureGeometry.cpp">
+      <Filter>Ogc</Filter>
+    </ClCompile>
     <ClCompile Include="HttpCsTransformCoordinates.cpp">
       <Filter>Coordinate System</Filter>
     </ClCompile>
@@ -817,6 +820,9 @@
     <ClInclude Include="HttpGeoBoundary.h">
       <Filter>GeoProcessing</Filter>
     </ClInclude>
+    <ClInclude Include="WmsFeatureGeometry.h">
+      <Filter>Ogc</Filter>
+    </ClInclude>
     <ClInclude Include="HttpCsTransformCoordinates.h">
       <Filter>Coordinate System</Filter>
     </ClInclude>

Modified: trunk/MgDev/Web/src/HttpHandler/HttpHandlerBuild.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpHandlerBuild.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/HttpHandlerBuild.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -152,6 +152,7 @@
 #include "WmsLayerDefinitions.cpp"
 #include "WmsFeatureInfo.cpp"
 #include "WmsFeatureProperties.cpp"
+#include "WmsFeatureGeometry.cpp"
 #include "WfsFeatureDefinitions.cpp"
 #include "XmlParser.cpp"
 #include "Dictionary.cpp"

Modified: trunk/MgDev/Web/src/HttpHandler/HttpWfsGetFeature.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpWfsGetFeature.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/HttpWfsGetFeature.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -291,20 +291,37 @@
                                 sSortCriteria  = sSortCriteria.substr(pos+1);
                             }
 
-                            // Call the C++ API
-                            // NOTE: I updated the maxFeatures value from numFeaturesToRetrieve to numFeaturesToRetrieve-1
-                            // Because the MgServerFdoFeatureReader in MapGuide server uses -1 to mark empty, while MgWfsFeatures
-                            // in MapGuide web tier uses 0
-                            resultReader = featureService->GetWfsFeature(featureSourceId, ((sSchemaHash.size()==0) ? sClass : sSchemaHash + _(":") + sClass),
-                                requiredProperties, m_getFeatureParams->GetSrs(), filter, numFeaturesToRetrieve-1, sVersion, sOutputFormat, sSortCriteria, sPrefix, oFeatureTypes.GetNamespaceUrl());
+                            //For GeoJSON, use the new GetWfsReader API
+                            if (sOutputFormat == MgMimeType::Json)
+                            {
+                                // NOTE: This API doesn't accept WFS version, format and XML namepaces because these are GML-isms baked into the GetWfsFeature API itself, making
+                                // it unsuitable for non-GML output, hence the need for this new GetWfsReader API
+                                Ptr<MgFeatureReader> fr = featureService->GetWfsReader(featureSourceId, ((sSchemaHash.size() == 0) ? sClass : sSchemaHash + _(":") + sClass),
+                                    requiredProperties, m_getFeatureParams->GetSrs(), filter, sSortCriteria);
+                                
+                                //MgByteSource owns this and will clean it up when done
+                                MgReaderByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(fr, MgMimeType::Json, true, false, -1);
+                                bsImpl->SetMaxFeatures(numFeaturesToRetrieve - 1);
+                                Ptr<MgByteSource> bs = new MgByteSource(bsImpl);
+                                resultReader = bs->GetReader();
+                            }
+                            else 
+                            {
+                                // Call the C++ API
+                                // NOTE: I updated the maxFeatures value from numFeaturesToRetrieve to numFeaturesToRetrieve-1
+                                // Because the MgServerFdoFeatureReader in MapGuide server uses -1 to mark empty, while MgWfsFeatures
+                                // in MapGuide web tier uses 0
+                                resultReader = featureService->GetWfsFeature(featureSourceId, ((sSchemaHash.size() == 0) ? sClass : sSchemaHash + _(":") + sClass),
+                                    requiredProperties, m_getFeatureParams->GetSrs(), filter, numFeaturesToRetrieve - 1, sVersion, sOutputFormat, sSortCriteria, sPrefix, oFeatureTypes.GetNamespaceUrl());
 
-                            // Store the MgByteReader directly for retrieval
-                            //
-                            // DO NOT PASS THROUGH OGC XML TEMPLATE PROCESSING CODE!
-                            // DO NOT PASS GO!
-                            // DO NOT COLLECT MEMORY SPIKES NEEDLESSLY BUFFERING XML TEMPLATE CONTENT AS A RESULT!
-                            //
-                            // This *is* already the WFS GetFeature response. There is nothing to post-process through the XML templates!
+                                // Store the MgByteReader directly for retrieval
+                                //
+                                // DO NOT PASS THROUGH OGC XML TEMPLATE PROCESSING CODE!
+                                // DO NOT PASS GO!
+                                // DO NOT COLLECT MEMORY SPIKES NEEDLESSLY BUFFERING XML TEMPLATE CONTENT AS A RESULT!
+                                //
+                                // This *is* already the WFS GetFeature response. There is nothing to post-process through the XML templates!
+                            }
                         }
                         else //Cannot resolve feature source from feature type name
                         {

Modified: trunk/MgDev/Web/src/HttpHandler/HttpWmsGetFeatureInfo.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpWmsGetFeatureInfo.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/HttpWmsGetFeatureInfo.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -154,9 +154,9 @@
     Ptr<MgCoordinate> mcsLowerLeft = mcsExtent->GetLowerLeftCoordinate();
     Ptr<MgCoordinate> mcsUpperRight = mcsExtent->GetUpperRightCoordinate();
 
-	//When GetFeatureInfo for point or line geometry, simply using click point to query cannot get any matching.
-	//Expand selection geometry a little to be a linearRing so that can query point and line.
-	double margin = 2;
+    //When GetFeatureInfo for point or line geometry, simply using click point to query cannot get any matching.
+    //Expand selection geometry a little to be a linearRing so that can query point and line.
+    double margin = 2;
     // Convert the pixel coords to MCS coords
     double mcsMinX = mcsLowerLeft->GetX() + ((double)m_iCoord - margin) * mcsExtent->GetWidth() / map->GetDisplayWidth();
     double mcsMaxY = mcsUpperRight->GetY() -((double)m_jCoord - margin) * mcsExtent->GetHeight() / map->GetDisplayHeight();
@@ -229,13 +229,17 @@
         // Get the selection geometry
         Ptr<MgGeometry> selectionGeometry = GetSelectionGeometry(map);
 
+        bool bCaptureGeometry = true;
+
         // Call the C++ API
         Ptr<MgBatchPropertyCollection> propertyCollection = service->QueryFeatureProperties(map, queryLayers, selectionGeometry,
-            MgFeatureSpatialOperations::Intersects, L"", m_featureCount, 1 /*Any visible features*/);
+            MgFeatureSpatialOperations::Intersects, L"", m_featureCount, 1 /*Any visible features*/, false /* no bbox */, bCaptureGeometry);
 
         // Create the object to store the feature info
         Ptr<MgWmsFeatureInfo> wmsFeatureInfo = new MgWmsFeatureInfo(propertyCollection);
 
+        wmsFeatureInfo->SetFormat(m_infoFormat);
+
         // The WMS Server takes ownership of the feature info
         wmsServer->SetFeatureInfo(wmsFeatureInfo);
     }

Modified: trunk/MgDev/Web/src/HttpHandler/Makefile.am
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/Makefile.am	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/Makefile.am	2017-11-26 22:22:40 UTC (rev 9256)
@@ -144,6 +144,7 @@
   ReaderByteSourceImpl.cpp \
   WfsFeatureDefinitions.cpp \
   WfsGetFeatureParams.cpp \
+  WmsFeatureGeometry.cpp \
   WmsFeatureInfo.cpp \
   WmsFeatureProperties.cpp \
   WmsLayerDefinitions.cpp \
@@ -290,6 +291,7 @@
   StringStream.h \
   WfsFeatureDefinitions.h \
   WfsGetFeatureParams.h \
+  WmsFeatureGeometry.h \
   WmsFeatureInfo.h \
   WmsFeatureProperties.h \
   WmsLayerDefinitions.h \

Modified: trunk/MgDev/Web/src/HttpHandler/OgcWmsServer.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/OgcWmsServer.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/OgcWmsServer.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -93,6 +93,7 @@
 
 CPSZ kpszPiEnumLayers                      = _("EnumLayers");
 CPSZ kpszPiEnumFeatureProperties           = _("EnumFeatureProperties");
+CPSZ kpszPiEnumFeatureGeometries           = _("EnumFeatureGeometries");
 CPSZ kpszPiEnumFeatureInfo                 = _("EnumFeatureInfo");
 extern CPSZ kpszPiAttributeUsing;  // for consistency, borrow the "using" attribute from base class.
 CPSZ kpszPiEnumLayersDefaultFormat         = _("&Layer.Name;\n");
@@ -784,6 +785,10 @@
     {
         ProcedureEnumFeatureInfo(PI);
     }
+    else if (sProc == kpszPiEnumFeatureGeometries)
+    {
+        ProcedureEnumFeatureGeometries(PI);
+    }
     else
     {
         return false;
@@ -863,6 +868,67 @@
     }
 }
 
+// Interpret a <?EnumFeatureGeometries using= ?> processing instruction
+// This will enumerate all feature geometries (only one)
+void MgOgcWmsServer::ProcedureEnumFeatureGeometries(MgXmlProcessingInstruction& PIEnum)
+{
+    STRING sFormat;
+    if (!PIEnum.GetAttribute(kpszPiAttributeUsing, sFormat))
+        sFormat = kpszPiEnumFeaturePropertiesDefaultFormat;
+
+    bool bIsGeometryEnabled = false;
+    if (m_pFeatureInfo != NULL && m_pLayers != NULL)
+    {
+        STRING layerName;
+        Ptr<MgWmsFeatureProperties> pProps = m_pFeatureInfo->GetCurrentProperties();
+        if (pProps != NULL)
+        {
+            layerName = pProps->GetLayerName();
+        }
+
+        //This will have been iterated previously, so rewind
+        m_pLayers->Reset();
+
+        while (m_pLayers->Next()) 
+        {
+            MgUtilDictionary currentDef(NULL);
+            m_pLayers->GenerateDefinitions(currentDef);
+
+            //We're at the layer of interest
+            CPSZ pszCurrentLayerName = currentDef[L"Layer.Name"];
+            if (SZ_EQ(pszCurrentLayerName, layerName.c_str()))
+            {
+                //Geometry data is only emitted if permitted by Layer.EnableGeometry
+                CPSZ pszEnableGeometry = currentDef[L"Layer.EnableGeometry"];
+                if (pszEnableGeometry != NULL && SZ_EQ(pszEnableGeometry, _("1")))
+                {
+                    bIsGeometryEnabled = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    CDictionaryStackFrame forFeatureGeometries(this);
+
+    if (m_pFeatureInfo != NULL)
+    {
+        Ptr<MgWmsFeatureProperties> pProps = m_pFeatureInfo->GetCurrentProperties();
+        if (pProps != NULL)
+        {
+            if (bIsGeometryEnabled)
+            {
+                Ptr<MgWmsFeatureGeometry> geom = pProps->GetGeometry();
+                while (geom->Next())
+                {
+                    geom->GenerateDefinitions(*m_pTopOfDefinitions);
+                    ProcessExpandableText(sFormat);
+                }
+            }
+        }
+    }
+}
+
 // Set the feature info (used for generating GetFeatureInfo response)
 void MgOgcWmsServer::SetFeatureInfo(MgWmsFeatureInfo* pFeatureInfo)
 {

Modified: trunk/MgDev/Web/src/HttpHandler/OgcWmsServer.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/OgcWmsServer.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/OgcWmsServer.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -24,6 +24,7 @@
 #include "WmsLayerDefinitions.h"
 #include "WmsFeatureInfo.h"
 #include "WmsFeatureProperties.h"
+#include "WmsFeatureGeometry.h"
 
 class MgOgcWmsServer: public MgOgcServer
 {
@@ -88,6 +89,7 @@
     void ProcedureEnumLayers            (MgXmlProcessingInstruction& PIEnum);
     void ProcedureEnumFeatureProperties (MgXmlProcessingInstruction& PIEnum);
     void ProcedureEnumFeatureInfo       (MgXmlProcessingInstruction& PIEnum);
+    void ProcedureEnumFeatureGeometries (MgXmlProcessingInstruction& PIEnum);
 
     bool ValidateGetCapabilitiesParameters();
     bool ValidateGetFeatureInfoParameters();

Modified: trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -18,6 +18,8 @@
 #include "PlatformBase.h"
 
 MgReaderByteSourceImpl::MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format, bool bCleanJson, bool bEnablePrecision, INT32 precision, MgTransform* xform)
+    : m_maxFeatures(-1),
+      m_featureIndex(-1)
 {
     m_reader = SAFE_ADDREF(reader);
     m_format = format;
@@ -42,6 +44,24 @@
     m_xform = NULL;
 }
 
+void MgReaderByteSourceImpl::SetMaxFeatures(INT32 maxFeatures)
+{
+    m_maxFeatures = maxFeatures;
+}
+
+bool MgReaderByteSourceImpl::ReadNextInternal()
+{
+    if (m_maxFeatures < 0 || m_featureIndex < m_maxFeatures)
+    {
+        m_featureIndex++;
+        return m_reader->ReadNext();
+    }
+    else
+    {
+        return false;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 /// \brief
 /// Reads a buffer
@@ -163,7 +183,7 @@
 
     if (m_bInternalReaderHasMore && bAdvanceReader)
     {
-        m_bInternalReaderHasMore = m_reader->ReadNext();
+        m_bInternalReaderHasMore = ReadNextInternal();
         if (m_bInternalReaderHasMore)
         {
             if (m_format == MgMimeType::Json)

Modified: trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/ReaderByteSourceImpl.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -80,7 +80,10 @@
     ///
     virtual void Rewind();
 
+    void SetMaxFeatures(INT32 maxFeatures);
+
 private:
+    bool ReadNextInternal();
     INT32 ReadInternalBuffer(BYTE_ARRAY_OUT buffer, INT32 fromIndex, INT32 length);
 
     Ptr<MgReader> m_reader;
@@ -91,6 +94,8 @@
     bool m_bInternalReaderHasMore;
     bool m_bFirstRecord;
     bool m_bEnablePrecision;
+    INT32 m_maxFeatures;
+    INT32 m_featureIndex;
 
     std::string m_buf;
     INT32 m_bufOffset;

Copied: trunk/MgDev/Web/src/HttpHandler/WmsFeatureGeometry.cpp (from rev 9255, sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.cpp)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/WmsFeatureGeometry.cpp	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/WmsFeatureGeometry.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -0,0 +1,77 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "OgcFramework.h"
+#include "WmsFeatureGeometry.h"
+
+MgWmsFeatureGeometry::MgWmsFeatureGeometry(MgGeometry * geom)
+    : m_bRead(false), m_format(MgMimeType::Text)
+{
+    m_geom = SAFE_ADDREF(geom);
+}
+
+MgWmsFeatureGeometry::~MgWmsFeatureGeometry()
+{
+    m_geom = NULL;
+}
+
+void MgWmsFeatureGeometry::SetFormat(CREFSTRING format)
+{
+    m_format = format;
+}
+
+bool MgWmsFeatureGeometry::Next()
+{
+    // Per the IOgcResourceEnumerator contract, we have to iterate, but we only want to iterate once
+    if (!m_bRead) 
+    {
+        m_bRead = true;
+        return true;
+    }
+    return false;
+}
+
+void MgWmsFeatureGeometry::GenerateDefinitions(MgUtilDictionary& dictionary)
+{
+    if (NULL != m_geom.p)
+    {
+        if (MgMimeType::Json == m_format) //Give GeoJSON geometry to json
+        {
+            MgGeoJsonWriter gjw;
+            STRING value;
+            gjw.ToGeoJson(m_geom, value, false);
+            dictionary.AddDefinition(_("FeatureGeometry.Value"), value);
+        }
+        else //Give everything else WKT
+        {
+            MgWktReaderWriter wktRw;
+            STRING value = wktRw.Write(m_geom);
+            dictionary.AddDefinition(_("FeatureGeometry.Value"), value);
+        }
+    }
+    else
+    {
+        if (MgMimeType::Json == m_format) 
+        {
+            dictionary.AddDefinition(_("FeatureGeometry.Value"), _("null"));
+        }
+        else 
+        {
+            dictionary.AddDefinition(_("FeatureGeometry.Value"), _(""));
+        }
+    }
+}

Copied: trunk/MgDev/Web/src/HttpHandler/WmsFeatureGeometry.h (from rev 9255, sandbox/jng/ogc/Web/src/HttpHandler/WmsFeatureGeometry.h)
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/WmsFeatureGeometry.h	                        (rev 0)
+++ trunk/MgDev/Web/src/HttpHandler/WmsFeatureGeometry.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -0,0 +1,49 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef _MgWmsFeatureInfoGeometry_h
+#define _MgWmsFeatureInfoGeometry_h
+
+#include "XmlParser.h"
+#include "Dictionary.h"
+
+class MgWmsFeatureGeometry : public IOgcResourceEnumerator, public MgDisposable
+{
+public:
+    MgWmsFeatureGeometry(MgGeometry* geom);
+    //Default constructor to keep Ptr<> happy
+    MgWmsFeatureGeometry() {};
+    virtual ~MgWmsFeatureGeometry();
+    
+    void SetFormat(CREFSTRING format);
+
+    bool Next();
+    void GenerateDefinitions(MgUtilDictionary& Dictionary);
+
+protected:
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+private:
+    Ptr<MgGeometry> m_geom;
+    bool m_bRead;
+    STRING m_format;
+};
+
+#endif
\ No newline at end of file

Modified: trunk/MgDev/Web/src/HttpHandler/WmsFeatureInfo.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/WmsFeatureInfo.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/WmsFeatureInfo.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -19,6 +19,7 @@
 #include "WmsFeatureInfo.h"
 #include "WmsFeatureProperties.h"
 
+CPSZ kpszIsLast = _("FeatureInfo.IsLast");
 CPSZ kpszDefinitionFeatureInfoLayerName = _("FeatureInfo.LayerName");
 CPSZ kpszLayerNameProperty = _("_MgLayerName");
 
@@ -59,9 +60,15 @@
                 dictionary.AddDefinition(kpszDefinitionFeatureInfoLayerName, value);
             }
         }
+        dictionary.AddDefinition(kpszIsLast, (m_index < m_propertyCollection->GetCount() - 1) ? L"0" : L"1");
     }
 }
 
+void MgWmsFeatureInfo::SetFormat(CREFSTRING format)
+{
+    m_format = format;
+}
+
 MgWmsFeatureProperties* MgWmsFeatureInfo::GetCurrentProperties()
 {
     MgWmsFeatureProperties* wmsProps = NULL;
@@ -71,6 +78,7 @@
         if(props != NULL)
         {
             wmsProps = new MgWmsFeatureProperties(props);
+            wmsProps->SetFormat(m_format);
         }
     }
     return wmsProps;

Modified: trunk/MgDev/Web/src/HttpHandler/WmsFeatureInfo.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/WmsFeatureInfo.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/WmsFeatureInfo.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -32,6 +32,8 @@
     MgWmsFeatureInfo(){};
     virtual ~MgWmsFeatureInfo();
 
+    void SetFormat(CREFSTRING format);
+
     bool Next();
     void GenerateDefinitions(MgUtilDictionary& Dictionary);
     MgWmsFeatureProperties* GetCurrentProperties();
@@ -45,6 +47,7 @@
 private:
    Ptr<MgBatchPropertyCollection> m_propertyCollection;
    int m_index;
+   STRING m_format;
 };
 
 #endif//_MgWmsFeatureInfo_h

Modified: trunk/MgDev/Web/src/HttpHandler/WmsFeatureProperties.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/WmsFeatureProperties.cpp	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/WmsFeatureProperties.cpp	2017-11-26 22:22:40 UTC (rev 9256)
@@ -20,7 +20,8 @@
 
 
 MgWmsFeatureProperties::MgWmsFeatureProperties(MgPropertyCollection* propertyCollection)
-:   m_index(-1)
+:   m_index(-1),
+    m_format(MgMimeType::Xml)
 {
     m_propertyCollection = SAFE_ADDREF(propertyCollection);
 }
@@ -29,15 +30,78 @@
 {
 }
 
+void MgWmsFeatureProperties::SetFormat(CREFSTRING format)
+{
+    m_format = format;
+}
+
+STRING MgWmsFeatureProperties::GetLayerName()
+{
+    STRING ret;
+    if (m_propertyCollection != NULL)
+    {
+        INT32 gidx = m_propertyCollection->IndexOf(_("_MgLayerName"));
+        if (gidx >= 0)
+        {
+            Ptr<MgProperty> prop = m_propertyCollection->GetItem(gidx);
+            if (prop->GetPropertyType() == MgPropertyType::String)
+            {
+                MgStringProperty* sp = static_cast<MgStringProperty*>(prop.p);
+                if (!sp->IsNull())
+                {
+                    ret = sp->GetValue();
+                }
+            }
+        }
+    }
+    return ret;
+}
+
+MgWmsFeatureGeometry* MgWmsFeatureProperties::GetGeometry()
+{
+    Ptr<MgWmsFeatureGeometry> ret;
+    Ptr<MgGeometry> geom = NULL;
+    if (m_propertyCollection != NULL)
+    {
+        INT32 gidx = m_propertyCollection->IndexOf(_("_MgGeometry"));
+        if (gidx >= 0)
+        {
+            Ptr<MgProperty> prop = m_propertyCollection->GetItem(gidx);
+            if (prop->GetPropertyType() == MgPropertyType::Geometry)
+            {
+                MgGeometryProperty* gp = static_cast<MgGeometryProperty*>(prop.p);
+                if (!gp->IsNull())
+                {
+                    Ptr<MgByteReader> agf = gp->GetValue();
+                    MgAgfReaderWriter agfRw;
+                    geom = agfRw.Read(agf);
+                }
+            }
+        }
+    }
+
+    ret = new MgWmsFeatureGeometry(geom);
+    ret->SetFormat(m_format);
+
+    return ret.Detach();
+}
+
+bool MgWmsFeatureProperties::IsSpecialProperty(MgProperty* prop)
+{
+    return (szcmp(prop->GetName().c_str(), _("_MgLayerName")) == 0)
+        || (szcmp(prop->GetName().c_str(), _("_MgGeometry")) == 0)
+        || (szcmp(prop->GetName().c_str(), _("_MgFeatureBoundingBox")) == 0);
+}
+
 bool MgWmsFeatureProperties::Next()
 {
     if(m_propertyCollection != NULL && m_index < m_propertyCollection->GetCount() - 1)
     {
         m_index++;
 
-        // Skip the special layer name property
+        // Skip the special properties
         Ptr<MgProperty> prop = m_propertyCollection->GetItem(m_index);
-        if(szcmp(prop->GetName().c_str(), _("_MgLayerName")) == 0)
+        if (IsSpecialProperty(prop))
         {
             return Next();
         }
@@ -53,18 +117,24 @@
 {
     if(m_propertyCollection != NULL && m_index >= 0 && m_index < m_propertyCollection->GetCount())
     {
-        Ptr<MgStringProperty> stringProp = (MgStringProperty*)m_propertyCollection->GetItem(m_index);
-        if(stringProp != NULL)
+        Ptr<MgProperty> prop = m_propertyCollection->GetItem(m_index);
+        STRING name = MgUtil::ReplaceEscapeCharInXml(prop->GetName());
+        // Skip the special properties
+        if (!IsSpecialProperty(prop))
         {
-            STRING name = MgUtil::ReplaceEscapeCharInXml(stringProp->GetName());
-
-            // Skip the special layer name property
-            if(szcmp(name.c_str(), _("_MgLayerName")) != 0)
+            STRING sIndex;
+            MgUtil::Int32ToString(m_index, sIndex);
+            if (prop->GetPropertyType() == MgPropertyType::String)
             {
+                MgStringProperty* stringProp = static_cast<MgStringProperty*>(prop.p);
                 STRING value = MgUtil::ReplaceEscapeCharInXml(stringProp->GetValue());
 
                 dictionary.AddDefinition(_("FeatureProperty.Name"), name.c_str());
                 dictionary.AddDefinition(_("FeatureProperty.Value"), value.c_str());
+                //A bit hack-ish but we need this for formats like GeoJSON so we know whether to insert a "," or not
+                //The server implementation will ensure that all the non-special properties are at the end of the collection
+                //ie. _MgLayerName, _MgGeometry, etc will never be the last property
+                dictionary.AddDefinition(_("FeatureProperty.IsLast"), (m_index == m_propertyCollection->GetCount() - 1) ? _("1") : _("0"));
             }
         }
     }

Modified: trunk/MgDev/Web/src/HttpHandler/WmsFeatureProperties.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/WmsFeatureProperties.h	2017-11-26 22:17:19 UTC (rev 9255)
+++ trunk/MgDev/Web/src/HttpHandler/WmsFeatureProperties.h	2017-11-26 22:22:40 UTC (rev 9256)
@@ -21,6 +21,8 @@
 #include "XmlParser.h"
 #include "Dictionary.h"
 
+class MgWmsFeatureGeometry;
+
 class MgWmsFeatureProperties: public IOgcResourceEnumerator, public MgDisposable
 {
 public:
@@ -30,8 +32,12 @@
     MgWmsFeatureProperties(){};
     virtual ~MgWmsFeatureProperties();
 
+    void SetFormat(CREFSTRING format);
+
     bool Next();
     void GenerateDefinitions(MgUtilDictionary& Dictionary);
+    MgWmsFeatureGeometry* GetGeometry();
+    STRING GetLayerName();
 
 protected:
     virtual void Dispose()
@@ -40,8 +46,10 @@
     }
 
 private:
-   Ptr<MgPropertyCollection> m_propertyCollection;
-   int m_index;
+    static bool IsSpecialProperty(MgProperty* prop);
+    Ptr<MgPropertyCollection> m_propertyCollection;
+    int m_index;
+    STRING m_format;
 };
 
 #endif//_MgWmsFeatureProperties_h



More information about the mapguide-commits mailing list