[mapguide-commits] r8265 - in sandbox/jng/convenience_apis: Common/MapGuideCommon/Services Common/PlatformBase/Services Server/src/Services/Feature Server/src/UnitTesting UnitTest/WebTier/DotNet/TestCommon/ExternalTests

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Thu Jun 26 07:31:04 PDT 2014


Author: jng
Date: 2014-06-26 07:31:04 -0700 (Thu, 26 Jun 2014)
New Revision: 8265

Added:
   sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.h
Modified:
   sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
   sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureDefs.h
   sandbox/jng/convenience_apis/Server/src/Services/Feature/FeatureOperationFactory.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/OpSelectFeatures.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureUtil.cpp
   sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureUtil.h
   sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.cpp
   sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.h
   sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs
Log:
This submission implements the MgFeatureService::SelectFeatures API that accepts a coordinate system parameter.

This API was previously not implemented.

Server and .net unit test included.

Modified: sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
===================================================================
--- sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2014-06-26 14:31:04 UTC (rev 8265)
@@ -584,11 +584,27 @@
                                                        MgFeatureQueryOptions* options,
                                                        CREFSTRING coordinateSystem)
 {
-    throw new MgNotImplementedException(
-        L"MgProxyFeatureService::SelectFeatures",
-        __LINE__, __WFILE__, NULL, L"", NULL);
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                  // Connection
+                       MgCommand::knObject,                         // Return type expected
+                       MgFeatureServiceOpId::SelectFeaturesWithTransform, // Command Code
+                       4,                                           // No of arguments
+                       Feature_Service,                             // Service Id
+                       BUILD_VERSION(3,0,0),                        // Operation version
+                       MgCommand::knObject, resource,               // Argument#1
+                       MgCommand::knString, &className,             // Argument#2
+                       MgCommand::knObject, options,                // Argument#3
+                       MgCommand::knString, &coordinateSystem,      // Argument#4
+                       MgCommand::knNone);                          // End of argument
 
-    return NULL; // to make some compiler happy
+    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);
 }
 
 

Modified: sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureDefs.h
===================================================================
--- sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureDefs.h	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Common/PlatformBase/Services/FeatureDefs.h	2014-06-26 14:31:04 UTC (rev 8265)
@@ -82,6 +82,7 @@
     static const int InsertFeatures2        = 0x1111ED32;
     static const int UpdateMatchingFeatures = 0x1111ED33;
     static const int DeleteFeatures         = 0x1111ED34;
+    static const int SelectFeaturesWithTransform = 0x1111ED35;
 };
 /// \endcond
 

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/FeatureOperationFactory.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/FeatureOperationFactory.cpp	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/FeatureOperationFactory.cpp	2014-06-26 14:31:04 UTC (rev 8265)
@@ -240,6 +240,18 @@
         }
         break;
 
+    case MgFeatureServiceOpId::SelectFeaturesWithTransform:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(3,0):
+            handler.reset(new MgOpSelectFeatures());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgFeatureOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
+
     case MgFeatureServiceOpId::SelectAggregate_Id:
         switch (VERSION_NO_PHASE(operationVersion))
         {

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/OpSelectFeatures.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/OpSelectFeatures.cpp	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/OpSelectFeatures.cpp	2014-06-26 14:31:04 UTC (rev 8265)
@@ -91,6 +91,39 @@
         // Write the response
         EndExecution(featureReader);
     }
+    else if (4 == m_packet.m_NumArguments)
+    {
+        // Get the feature source
+        Ptr<MgResourceIdentifier> resource = (MgResourceIdentifier*)m_stream->GetObject();
+        // Get the schema name
+        STRING className;
+        m_stream->GetString(className);
+
+        // Get properties collection
+        Ptr<MgFeatureQueryOptions> qryOptions = (MgFeatureQueryOptions*)m_stream->GetObject();
+        STRING coordinateSystem;
+        m_stream->GetString(coordinateSystem);
+
+        BeginExecution();
+
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING((NULL == resource) ? L"MgResourceIdentifier" : resource->ToString().c_str());
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(className.c_str());
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(L"MgFeatureQueryOptions");
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(L"STRING");
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        // Execute the operation
+        Ptr<MgFeatureReader> featureReader = m_service->SelectFeatures(resource, className, qryOptions, coordinateSystem);
+
+        // Write the response
+        EndExecution(featureReader);
+    }
     else
     {
         MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.cpp	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.cpp	2014-06-26 14:31:04 UTC (rev 8265)
@@ -47,6 +47,7 @@
 #include "ServerDataReader.h"
 #include "ServerSqlDataReader.h"
 #include "ServerFeatureTransaction.h"
+#include "TransformedGeometryFeatureReader.h"
 
 #include <Fdo/Xml/FeatureSerializer.h>
 #include <Fdo/Xml/FeatureWriter.h>
@@ -507,11 +508,46 @@
                                                         MgFeatureQueryOptions* options,
                                                         CREFSTRING coordinateSystem)
 {
-    throw new MgNotImplementedException(
-        L"MgServerFeatureService::SelectFeatures",
-        __LINE__, __WFILE__, NULL, L"", NULL);
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::SelectFeatures()");
 
-    return NULL; // to make some compiler happy
+    Ptr<MgFeatureReader> reader;
+
+    MG_FEATURE_SERVICE_TRY()
+
+    if (NULL == resource)
+    {
+        throw new MgNullArgumentException(
+            L"MgServerFeatureService.SelectFeatures", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MgLogDetail logDetail(MgServiceType::FeatureService, MgLogDetail::Trace, L"MgServerFeatureService.SelectFeatures",mgStackParams);
+    logDetail.AddResourceIdentifier(L"Resource", resource);
+    logDetail.AddString(L"ClassName", className);
+    logDetail.AddObject(L"Options", options);
+    logDetail.AddString(L"CoordinateSystem", coordinateSystem);
+    logDetail.Create();
+
+    MgServerSelectFeatures mssf;
+    Ptr<MgFeatureReader> innerReader = (MgFeatureReader*)mssf.SelectFeatures(resource, className, options, false);
+
+    Ptr<MgCoordinateSystemTransform> xform;
+    STRING srcCsWkt = MgServerFeatureUtil::GetSpatialContextCoordSys(this, resource, className);
+    if (!srcCsWkt.empty() && !coordinateSystem.empty())
+    {
+        Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+        Ptr<MgCoordinateSystem> srcCs = csFactory->Create(srcCsWkt);
+        Ptr<MgCoordinateSystem> dstCs = csFactory->Create(coordinateSystem);
+        xform = csFactory->GetTransform(srcCs, dstCs);
+        reader = new MgTransformedGeometryFeatureReader(innerReader, xform);
+    }
+    else
+    {
+        reader = SAFE_ADDREF((MgFeatureReader*)innerReader);
+    }
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW_WITH_FEATURE_SOURCE(L"MgServerFeatureService.SelectFeatures", resource)
+
+    return reader.Detach();
 }
 
 

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj	2014-06-26 14:31:04 UTC (rev 8265)
@@ -810,6 +810,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="TransformedGeometryFeatureReader.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" />
@@ -934,6 +940,7 @@
     <ClInclude Include="..\..\Common\stdafx.h" />
     <ClInclude Include="StringDataReaderCreator.h" />
     <ClInclude Include="TransformCache.h" />
+    <ClInclude Include="TransformedGeometryFeatureReader.h" />
     <ClInclude Include="UniqueFunction.h" />
   </ItemGroup>
   <ItemGroup>

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2014-06-26 14:31:04 UTC (rev 8265)
@@ -200,6 +200,7 @@
     <ClCompile Include="OpInsertFeaturesBatched.cpp">
       <Filter>Ops</Filter>
     </ClCompile>
+    <ClCompile Include="TransformedGeometryFeatureReader.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="FeatureOperation.h">
@@ -409,6 +410,7 @@
     <ClInclude Include="OpInsertFeaturesBatched.h">
       <Filter>Ops</Filter>
     </ClInclude>
+    <ClInclude Include="TransformedGeometryFeatureReader.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ServerFeatureService.rc" />

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2014-06-26 14:31:04 UTC (rev 8265)
@@ -111,3 +111,4 @@
 #include "OpInsertFeaturesBatched.cpp"
 #include "OpUpdateMatchingFeatures.cpp"
 #include "OpDeleteFeatures.cpp"
+#include "TransformedGeometryFeatureReader.cpp"

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureUtil.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureUtil.cpp	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureUtil.cpp	2014-06-26 14:31:04 UTC (rev 8265)
@@ -3624,3 +3624,38 @@
     MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgServerFeatureUtil.ExtractIdentifiers")
     return ret.Detach();
 }
+
+STRING MgServerFeatureUtil::GetSpatialContextCoordSys(MgFeatureService* featSvc, MgResourceIdentifier* featureSourceId, CREFSTRING className)
+{
+    STRING ret;
+    MG_FEATURE_SERVICE_TRY()
+
+    STRING schema;
+    STRING klass;
+
+    MgUtil::ParseQualifiedClassName(className, schema, klass);
+
+    Ptr<MgClassDefinition> clsDef = featSvc->GetClassDefinition(featureSourceId, schema, klass);
+    Ptr<MgPropertyDefinitionCollection> clsProps = clsDef->GetProperties();
+    INT32 gidx = clsProps->IndexOf(clsDef->GetDefaultGeometryPropertyName());
+    if (gidx >= 0)
+    {
+        Ptr<MgPropertyDefinition> propDef = clsProps->GetItem(gidx);
+        if (propDef->GetPropertyType() == MgFeaturePropertyType::GeometricProperty)
+        {
+            STRING scName = ((MgGeometricPropertyDefinition*)propDef.p)->GetSpatialContextAssociation();
+            Ptr<MgSpatialContextReader> scReader = featSvc->GetSpatialContexts(featureSourceId, false);
+            while(scReader->ReadNext())
+            {
+                if (scReader->GetName() == scName)
+                {
+                    ret = scReader->GetCoordinateSystemWkt();
+                    break;
+                }
+            }
+            scReader->Close();
+        }
+    }
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgServerFeatureUtil.GetSpatialContextCoordSys")
+    return ret;
+}
\ No newline at end of file

Modified: sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureUtil.h
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureUtil.h	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/ServerFeatureUtil.h	2014-06-26 14:31:04 UTC (rev 8265)
@@ -130,6 +130,8 @@
     static void UpdateObjectPropertyDefinition(MgObjectPropertyDefinition* objPropDef, FdoObjectPropertyDefinition* fdoPropDef, FdoClassCollection* fdoClassCol);
     static void UpdateGeometricPropertyDefinition(MgGeometricPropertyDefinition* mgPropDef, FdoGeometricPropertyDefinition* fdoPropDef);
     static void UpdateRasterPropertyDefinition(MgRasterPropertyDefinition* mgPropDef, FdoRasterPropertyDefinition* fdoPropDef);
+
+    static STRING GetSpatialContextCoordSys(MgFeatureService* featSvc, MgResourceIdentifier* featureSourceId, CREFSTRING className);
 private:
     static bool Initialize();
 

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.cpp	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.cpp	2014-06-26 14:31:04 UTC (rev 8265)
@@ -0,0 +1,520 @@
+//
+//  Copyright (C) 2004-2014 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 "MapGuideCommon.h"
+#include "TransformedGeometryFeatureReader.h"
+
+MgTransformedGeometryFeatureReader::MgTransformedGeometryFeatureReader(MgFeatureReader* reader, MgCoordinateSystemTransform* transform)
+{
+    m_innerReader = SAFE_ADDREF(reader);
+    m_transform = SAFE_ADDREF(transform);
+    m_agfRw = new MgAgfReaderWriter();
+}
+
+MgTransformedGeometryFeatureReader::~MgTransformedGeometryFeatureReader()
+{
+    m_innerReader = NULL;
+    m_transform = NULL;
+    m_agfRw = NULL;
+}
+
+MgByteReader* MgTransformedGeometryFeatureReader::GetGeometry(INT32 index)
+{
+    Ptr<MgByteReader> ret;
+
+    MG_FEATURE_SERVICE_TRY()
+
+    Ptr<MgByteReader> agf = ((MgReader*)m_innerReader)->GetGeometry(index);
+    Ptr<MgGeometry> geom = m_agfRw->Read(agf, m_transform);
+    ret = m_agfRw->Write(geom);
+    
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetGeometry")
+
+    return ret.Detach();
+}
+
+MgByteReader* MgTransformedGeometryFeatureReader::GetGeometry(CREFSTRING name)
+{
+    Ptr<MgByteReader> ret;
+
+    MG_FEATURE_SERVICE_TRY()
+
+    Ptr<MgByteReader> agf = ((MgReader*)m_innerReader)->GetGeometry(name);
+    Ptr<MgGeometry> geom = m_agfRw->Read(agf, m_transform);
+    ret = m_agfRw->Write(geom);
+
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetGeometry")
+
+    return ret.Detach();
+}
+
+void MgTransformedGeometryFeatureReader::Close() 
+{
+    MG_FEATURE_SERVICE_TRY()
+    m_innerReader->Close();
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.Close")
+}
+
+bool MgTransformedGeometryFeatureReader::ReadNext() 
+{ 
+    bool ret = false;
+    MG_FEATURE_SERVICE_TRY()
+    ret = m_innerReader->ReadNext(); 
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.ReadNext")
+    return ret;
+}
+
+bool MgTransformedGeometryFeatureReader::IsNull(CREFSTRING propertyName) 
+{ 
+    bool ret = false;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->IsNull(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.IsNull")
+    return ret;
+}
+
+bool MgTransformedGeometryFeatureReader::GetBoolean(CREFSTRING propertyName) 
+{ 
+    bool ret = false;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetBoolean(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetBoolean")
+    return ret;
+}
+
+BYTE MgTransformedGeometryFeatureReader::GetByte(CREFSTRING propertyName) 
+{ 
+    BYTE ret = 0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetByte(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetByte")
+    return ret;
+}
+
+MgDateTime* MgTransformedGeometryFeatureReader::GetDateTime(CREFSTRING propertyName) 
+{ 
+    Ptr<MgDateTime> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetDateTime(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetDateTime")
+    return ret.Detach();
+}
+
+float MgTransformedGeometryFeatureReader::GetSingle(CREFSTRING propertyName) 
+{ 
+    float ret = 0.0f;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetSingle(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetSingle")
+    return ret;
+}
+
+double MgTransformedGeometryFeatureReader::GetDouble(CREFSTRING propertyName) 
+{ 
+    double ret = 0.0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetDouble(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetDouble")
+    return ret;
+}
+
+INT16 MgTransformedGeometryFeatureReader::GetInt16(CREFSTRING propertyName) 
+{ 
+    INT16 ret = 0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetInt16(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetInt16")
+    return ret;
+}
+
+INT32 MgTransformedGeometryFeatureReader::GetInt32(CREFSTRING propertyName) 
+{ 
+    INT32 ret = 0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetInt32(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetInt32")
+    return ret;
+}
+
+INT64 MgTransformedGeometryFeatureReader::GetInt64(CREFSTRING propertyName) 
+{ 
+    INT64 ret = 0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetInt64(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetInt32")
+    return ret;
+}
+
+STRING MgTransformedGeometryFeatureReader::GetString(CREFSTRING propertyName) 
+{ 
+    STRING ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetString(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetString")
+    return ret;
+}
+
+MgByteReader* MgTransformedGeometryFeatureReader::GetBLOB(CREFSTRING propertyName) 
+{ 
+    Ptr<MgByteReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetBLOB(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetBLOB")
+    return ret.Detach();
+}
+
+MgByteReader* MgTransformedGeometryFeatureReader::GetCLOB(CREFSTRING propertyName)
+{ 
+    Ptr<MgByteReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetCLOB(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetCLOB")
+    return ret.Detach();
+}
+
+//This won't be used by RS_FeatureReader because stylization will use SelectFeatures()
+//that will not return this type of reader
+BYTE_ARRAY_OUT MgTransformedGeometryFeatureReader::GetGeometry(CREFSTRING propertyName, INT32& length) 
+{ 
+    throw new MgNotImplementedException(L"MgTransformedGeometryFeatureReader.GetGeometry", __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+//This won't be used by RS_FeatureReader because stylization will use SelectFeatures()
+//that will not return this type of reader
+BYTE_ARRAY_OUT MgTransformedGeometryFeatureReader::GetGeometry(INT32 index, INT32& length) 
+{ 
+    throw new MgNotImplementedException(L"MgTransformedGeometryFeatureReader.GetGeometry", __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+MgRaster* MgTransformedGeometryFeatureReader::GetRaster(CREFSTRING propertyName) 
+{ 
+    Ptr<MgRaster> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetRaster(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetRaster")
+    return ret.Detach();
+}
+
+//MgByteReader* MgTransformedGeometryFeatureReader::GetRaster(STRING rasterPropName, INT32 xSize, INT32 ySize)
+//{
+//    return m_innerReader->GetRaster(rasterPropName, xSize, ySize);
+//}
+
+bool MgTransformedGeometryFeatureReader::IsNull(INT32 index) 
+{ 
+    bool ret = false;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->IsNull(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.IsNull")
+    return ret;
+}
+
+bool MgTransformedGeometryFeatureReader::GetBoolean(INT32 index) 
+{
+    bool ret = false;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetBoolean(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetBoolean")
+    return ret;
+}
+
+BYTE MgTransformedGeometryFeatureReader::GetByte(INT32 index) 
+{ 
+    BYTE ret = 0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetByte(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetByte")
+    return ret;
+}
+
+MgDateTime* MgTransformedGeometryFeatureReader::GetDateTime(INT32 index) 
+{ 
+    Ptr<MgDateTime> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetDateTime(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetDateTime")
+    return ret.Detach();
+}
+
+float MgTransformedGeometryFeatureReader::GetSingle(INT32 index) 
+{ 
+    float ret = 0.0f;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetSingle(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetSingle")
+    return ret;
+}
+
+double MgTransformedGeometryFeatureReader::GetDouble(INT32 index) 
+{ 
+    double ret = 0.0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetDouble(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetDouble")
+    return ret;
+}
+
+INT16 MgTransformedGeometryFeatureReader::GetInt16(INT32 index) 
+{ 
+    INT16 ret = 0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetInt16(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetInt16")
+    return ret;
+}
+
+INT32 MgTransformedGeometryFeatureReader::GetInt32(INT32 index)
+{ 
+    INT32 ret = 0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetInt32(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetInt32")
+    return ret;
+}
+
+INT64 MgTransformedGeometryFeatureReader::GetInt64(INT32 index) 
+{ 
+    INT64 ret = 0;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetInt64(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetInt64")
+    return ret;
+}
+
+STRING MgTransformedGeometryFeatureReader::GetString(INT32 index) 
+{ 
+    STRING ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetString(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetString")
+    return ret;
+}
+
+MgByteReader* MgTransformedGeometryFeatureReader::GetBLOB(INT32 index) 
+{ 
+    Ptr<MgByteReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetBLOB(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetBLOB")
+    return ret.Detach();
+}
+
+MgByteReader* MgTransformedGeometryFeatureReader::GetCLOB(INT32 index) 
+{ 
+    Ptr<MgByteReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetCLOB(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetCLOB")
+    return ret.Detach();
+}
+
+MgRaster* MgTransformedGeometryFeatureReader::GetRaster(INT32 index) 
+{ 
+    Ptr<MgRaster> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetRaster(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetRaster")
+    return ret.Detach();
+}
+
+INT32 MgTransformedGeometryFeatureReader::GetReaderType() 
+{ 
+	return m_innerReader->GetReaderType();
+}
+
+//EXTERNAL_API:
+
+MgByteReader* MgTransformedGeometryFeatureReader::ToXml() 
+{ 
+    Ptr<MgByteReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->ToXml();
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.ToXml")
+    return ret.Detach();
+}
+
+//INTERNAL_API:
+
+string MgTransformedGeometryFeatureReader::GetResponseElementName()
+{
+    return m_innerReader->GetResponseElementName();
+}
+
+string MgTransformedGeometryFeatureReader::GetBodyElementName()
+{
+    return m_innerReader->GetBodyElementName();
+}
+
+void MgTransformedGeometryFeatureReader::ResponseStartUtf8(string& str)
+{
+    m_innerReader->ResponseStartUtf8(str);
+}
+
+void MgTransformedGeometryFeatureReader::ResponseEndUtf8(string& str)
+{
+    m_innerReader->ResponseEndUtf8(str);
+}
+
+void MgTransformedGeometryFeatureReader::BodyStartUtf8(string& str)
+{
+    m_innerReader->BodyStartUtf8(str);
+}
+
+void MgTransformedGeometryFeatureReader::BodyEndUtf8(string& str)
+{
+    m_innerReader->BodyEndUtf8(str);
+}
+
+void MgTransformedGeometryFeatureReader::CurrentToStringUtf8(string& str)
+{
+    m_innerReader->CurrentToStringUtf8(str);
+}
+
+void MgTransformedGeometryFeatureReader::HeaderToStringUtf8(string& str)
+{
+    m_innerReader->HeaderToStringUtf8(str);
+}
+
+const wchar_t* MgTransformedGeometryFeatureReader::GetString(CREFSTRING propertyName, INT32& length) 
+{
+	return m_innerReader->GetString(propertyName, length);
+}
+
+void MgTransformedGeometryFeatureReader::Serialize(MgStream* stream) 
+{ 
+    INT32 count = 1; // Get value from MgConfiguration
+    bool operationCompleted = false;
+    Ptr<MgFeatureSet> featureSet;
+    STRING featureReader = L"";
+
+    MG_FEATURE_SERVICE_TRY()
+
+    // Find out the counts from Configuration
+    MgConfiguration* config = MgConfiguration::GetInstance();
+
+    config->GetIntValue(MgConfigProperties::FeatureServicePropertiesSection,
+                        MgConfigProperties::FeatureServicePropertyDataCacheSize,
+                        count,
+                        MgConfigProperties::DefaultFeatureServicePropertyDataCacheSize);
+
+    // Collect the feature reader into a pool for ReadNext operation
+    MgServerFeatureReaderPool* featPool = MgServerFeatureReaderPool::GetInstance();
+    CHECKNULL(featPool, L"MgTransformedGeometryFeatureReader.Serialize");
+
+    featureReader = featPool->GetReaderId(this);
+    if (L"" == featureReader)
+    {
+        // The feature reader is not in the pool
+        featureReader = featPool->Add(this); // Add the reference
+    }
+
+    featureSet = GetFeatures(count);
+
+    operationCompleted = true;
+
+    MG_FEATURE_SERVICE_CATCH(L"MgTransformedGeometryFeatureReader.Serialize");
+
+    // Mark operation is completed successfully
+    stream->WriteBoolean(operationCompleted);
+
+    if (operationCompleted && (mgException == 0))
+    {
+        stream->WriteString(featureReader); // Write the reader ID so we can retrieve it for later use
+        stream->WriteObject((MgFeatureSet*)featureSet); // Write the feature set
+    }
+    else
+    {
+        stream->WriteObject((MgException*)mgException);
+    }
+}
+
+void MgTransformedGeometryFeatureReader::Deserialize(MgStream* stream) 
+{ 
+    throw new MgInvalidOperationException(L"MgTransformedGeometryFeatureReader.Deserialize",
+        __LINE__, __WFILE__, NULL, L"", NULL);
+}
+
+//MgFeatureReader
+//PUBLISHED_API:
+MgClassDefinition* MgTransformedGeometryFeatureReader::GetClassDefinition() 
+{ 
+    Ptr<MgClassDefinition> ret;
+    MG_FEATURE_SERVICE_TRY()
+    ret = m_innerReader->GetClassDefinition();
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetClassDefinition")
+    return ret.Detach();
+}
+
+//This is internal, but MgdMappingUtil needs it. So we have to implement it
+MgClassDefinition* MgTransformedGeometryFeatureReader::GetClassDefinitionNoXml() 
+{ 
+    Ptr<MgClassDefinition> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetClassDefinitionNoXml();
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetClassDefinitionNoXml")
+    return ret.Detach();
+}
+
+MgFeatureReader* MgTransformedGeometryFeatureReader::GetFeatureObject(CREFSTRING propertyName) 
+{ 
+    Ptr<MgFeatureReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetFeatureObject(propertyName);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetFeatureObject")
+    return ret.Detach();
+}
+
+MgFeatureReader* MgTransformedGeometryFeatureReader::GetFeatureObject(INT32 index) 
+{ 
+    Ptr<MgFeatureReader> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetFeatureObject(index);
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetFeatureObject")
+    return ret.Detach();
+}
+
+//INTERNAL_API:
+
+MgFeatureSet* MgTransformedGeometryFeatureReader::GetFeatures(INT32 count) 
+{ 
+    Ptr<MgFeatureSet> ret;
+    MG_FEATURE_SERVICE_TRY()
+	ret = m_innerReader->GetFeatures(count);
+    if (NULL != m_transform.p)
+    {
+        for (INT32 i = 0; i < ret->GetCount(); i++)
+        {
+            Ptr<MgPropertyCollection> props = ret->GetFeatureAt(i);
+            for (INT32 j = 0; j < props->GetCount(); j++)
+            {
+                Ptr<MgProperty> prop = props->GetItem(j);
+                if (prop->GetPropertyType() == MgPropertyType::Geometry)
+                {
+                    MgGeometryProperty* geomProp = static_cast<MgGeometryProperty*>(prop.p);
+                    if (!geomProp->IsNull())
+                    {
+                        Ptr<MgByteReader> agf = geomProp->GetValue();
+                        Ptr<MgGeometry> geom = m_agfRw->Read(agf, m_transform);
+                        Ptr<MgByteReader> txAgf = m_agfRw->Write(geom);
+                        geomProp->SetValue(txAgf);
+                    }
+                }
+            }
+        }
+    }
+    MG_FEATURE_SERVICE_CATCH_AND_THROW(L"MgTransformedGeometryFeatureReader.GetFeatures")
+    return ret.Detach();
+}
\ No newline at end of file

Added: sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.h
===================================================================
--- sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.h	                        (rev 0)
+++ sandbox/jng/convenience_apis/Server/src/Services/Feature/TransformedGeometryFeatureReader.h	2014-06-26 14:31:04 UTC (rev 8265)
@@ -0,0 +1,528 @@
+//
+//  Copyright (C) 2004-2014 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_TRANSFORMED_GEOMETRY_FEATURE_READER_H_
+#define _MG_TRANSFORMED_GEOMETRY_FEATURE_READER_H_
+
+//
+// A feature reader that transforms any geometries read from it
+//
+class MG_SERVER_FEATURE_API MgTransformedGeometryFeatureReader : public MgFeatureReader
+{
+EXTERNAL_API:
+    MgTransformedGeometryFeatureReader(MgFeatureReader* inner, MgCoordinateSystemTransform* xform);
+    virtual ~MgTransformedGeometryFeatureReader();
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Advances the reader to the next item and returns true if there is
+    /// another object to read or false if reading is complete. The default
+    /// position of the reader is prior to the first item. Thus you must
+    /// call ReadNext to begin accessing any data.
+    /// </summary>
+    /// <returns>
+    /// Returns true if there is a next item.
+    /// </returns>
+    bool ReadNext();
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the definition of the object currently being read. If the user
+    /// has requested only a subset of the class properties, the class
+    /// definition reflects what the user has asked, rather than the full class
+    /// definition.
+    /// </summary>
+    /// <returns>A MgClassDefinition representing the current object
+    ///</returns>
+    MgClassDefinition* GetClassDefinition();
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    ///  Returns true if the value of the specified property is null.
+    /// </summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns true if the value is null.</returns>
+    bool IsNull(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Boolean value of the specified property. No conversion is
+    /// performed, thus the property must be a of boolean type the result
+    /// is undertermined</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the Boolean value.</returns>
+    bool GetBoolean(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Byte value of the specified property. No conversion is
+    /// performed, thus the property must be a of byte type or the result
+    /// is undertermined</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the Byte value.</returns>
+    BYTE GetByte(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the DTime value of the specified property. No conversion is
+    /// performed, thus the property must be a of date type or the result
+    /// is NULL</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the DTime value.</returns>
+    MgDateTime* GetDateTime(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Single value of the specified property. No conversion is
+    /// performed, thus the property must be a of type single or the result
+    /// is undetermined</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the single value.</returns>
+    float GetSingle(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Double value of the specified property. No conversion is
+    /// performed, thus the property must be a of type double or the result
+    /// is undetermined</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the double value.</returns>
+    double GetDouble(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the integer 16 bits value of the specified property. No conversion is
+    /// performed, thus the property must be a of type integer 16 bits or the result
+    /// is undetermined</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the integer 16 bits value.</returns>
+    INT16 GetInt16(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the integer 32 bits value of the specified property. No conversion is
+    /// performed, thus the property must be a of type integer 32 bits or the result
+    /// is undetermined</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the integer 32 bits value.</returns>
+    INT32 GetInt32(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the integer 64 bits value of the specified property. No conversion is
+    /// performed, thus the property must be a of type integer 64 bits or the result
+    /// is NULL</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the integer 64 bits value.
+    /// Note: INT64 is actually a pointer to an Integer64 object
+    ///</returns>
+    INT64 GetInt64(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the string value of the specified property. No conversion is
+    /// performed, thus the property must be a of type string or the result
+    /// is NULL</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the string value.</returns>
+    STRING GetString(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the BLOB value of the specified property. No conversion is
+    /// performed, thus the property must be a of type BLOBs or the result
+    /// is NULL</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the BLOB value.</returns>
+    MgByteReader* GetBLOB(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the CLOB value of the specified property. No conversion is
+    /// performed, thus the property must be a of type CLOB or the result
+    /// is NULL</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the CLOB value.</returns>
+    MgByteReader* GetCLOB(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the FeatureReader to access this object value.
+    /// The property must be of an object type; otherwise, the result is NULL.
+    /// </summary>
+    /// <param name="propertyName">Input the property name.</param>
+    /// <returns>Returns the feature reader to access this object.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not a feature
+    MgFeatureReader* GetFeatureObject(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Geometry for the specified property. No conversion is
+    /// performed, thus the property must be a of type Geometry or the result
+    /// is NULL</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns a ByteReader object</returns>
+    MgByteReader* GetGeometry(CREFSTRING propertyName);
+
+    /// <summary>Gets the raster object of the specified property.
+    /// the property must be of Raster type; otherwise, an exception is thrown.
+    /// </summary>
+    /// <param name="propertyName">Input the property name.</param>
+    /// <returns>Returns the raster object.</returns>
+    /// EXCEPTIONS:
+    /// MgConnectionNotOpenException
+    /// MgNullPropertyValueException
+    /// MgFdoException
+    MgRaster* GetRaster(CREFSTRING propertyName);
+
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    ///  Returns true if the value of the property at the specified index is null.
+    /// </summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns true if the value is null.</returns>
+    bool IsNull(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Boolean value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of boolean type the result
+    /// is undertermined</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the Boolean value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not boolean
+    bool GetBoolean(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Byte value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of byte type or the result
+    /// is undertermined</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the Byte value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not byte
+    BYTE GetByte(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the DTime value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of date type or the result
+    /// is NULL</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the DTime value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not date/time
+    MgDateTime* GetDateTime(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Single value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of type single or the result
+    /// is undetermined</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the single value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not float
+    float GetSingle(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Double value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of type double or the result
+    /// is undetermined</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the double value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not double
+    double GetDouble(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the integer 16 bits value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of type integer 16 bits or the result
+    /// is undetermined</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the integer 16 bits value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not int16
+    INT16 GetInt16(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the integer 32 bits value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of type integer 32 bits or the result
+    /// is undetermined</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the integer 32 bits value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not int32
+    INT32 GetInt32(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the integer 64 bits value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of type integer 64 bits or the result
+    /// is NULL</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the integer 64 bits value.
+    /// Note: INT64 is actually a pointer to an Integer64 object
+    ///</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not int64
+    INT64 GetInt64(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the string value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of type string or the result
+    /// is NULL</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the string value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not a string
+    STRING GetString(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the BLOB value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of type BLOBs or the result
+    /// is NULL</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the BLOB value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not a BLOB
+    MgByteReader* GetBLOB(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the CLOB value of the property at the specified index. No conversion is
+    /// performed, thus the property must be a of type CLOB or the result
+    /// is NULL</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the CLOB value.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not a CLOB
+    MgByteReader* GetCLOB(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the FeatureReader to access this object value.
+    /// The property must be of an object type; otherwise, the result is NULL.
+    /// </summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the feature reader to access this object.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not a feature
+    MgFeatureReader* GetFeatureObject(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the geometry value of the property at the specified index as a GeometryReader.
+    /// Because no conversion is performed, the property must be
+    /// of Geometric type; otherwise, the result is NULL.</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the Geometry object.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not geometry
+    MgByteReader* GetGeometry(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// </summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns the Raster object.</returns>
+    /// EXCEPTIONS:
+    /// MgInvalidArgumentException if the property type is not geometry
+    MgRaster* GetRaster(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Closes the FeatureReader object, freeing any resources it may be holding.
+    /// </summary>
+    void Close();
+
+    INT32 GetReaderType();
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the starting element name as a UTF-8 string. The mime
+    /// type must be a text type, for example text/xml.
+    ///
+    /// \param str
+    /// Destination string.
+    ///
+    string GetResponseElementName();
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the body starting element name as a UTF-8 string. The mime
+    /// type must be a text type, for example text/xml.
+    ///
+    /// \param str
+    /// Destination string.
+    ///
+    string GetBodyElementName();
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the start of the response as a UTF-8 string. The mime
+    /// type must be a text type, for example text/xml.
+    ///
+    /// \param str
+    /// Destination string.
+    ///
+    void ResponseStartUtf8(string& str);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the end of the response as a UTF-8 string. The mime
+    /// type must be a text type, for example text/xml.
+    ///
+    /// \param str
+    /// Destination string.
+    ///
+    void ResponseEndUtf8(string& str);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the start of the response body as a UTF-8 string. The mime
+    /// type must be a text type, for example text/xml.
+    ///
+    /// \param str
+    /// Destination string.
+    ///
+    void BodyStartUtf8(string& str);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the end of the response body as a UTF-8 string. The mime
+    /// type must be a text type, for example text/xml.
+    ///
+    /// \param str
+    /// Destination string.
+    ///
+    void BodyEndUtf8(string& str);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the contents of the header in this reader as a UTF-8 string.  The mime
+    /// type must be a text type, for example text/xml.
+    ///
+    /// \param str
+    /// Destination string.
+    ///
+    void HeaderToStringUtf8(string& str);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the contents of the current record/feature in the reader as a UTF-8 string.  The mime
+    /// type must be a text type, for example text/xml.
+    ///
+    /// \param str
+    /// Destination string.
+    ///
+    void CurrentToStringUtf8(string& str);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Serializes all features into an XML.
+    /// XML is serialized from the current position of feature reader in the order
+    /// data are retrieved.
+    /// <returns>MgByteReader holding XML.</returns>
+    MgByteReader* ToXml();
+
+protected:
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+INTERNAL_API:
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the definition of the object currently being read. If the user
+    /// has requested only a subset of the class properties, the class
+    /// definition reflects what the user has asked, rather than the full class
+    /// definition.
+    /// </summary>
+    /// <returns>A MgClassDefinition representing the current object
+    ///</returns>
+    /// NOTE: This is internal API used by the mapping service
+    /// in the case where we do not want to spend time
+    /// serializing the class definition to XML
+    MgClassDefinition* GetClassDefinitionNoXml();
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Geometry for the specified property. No conversion is
+    /// performed, thus the property must be a of type Geometry or the result
+    /// is NULL</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns a ByteReader object</returns>
+    BYTE_ARRAY_OUT GetGeometry(CREFSTRING propertyName, INT32& length);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the Geometry for the specified property. No conversion is
+    /// performed, thus the property must be a of type Geometry or the result
+    /// is NULL</summary>
+    /// <param name="index">Property index.</param>
+    /// <returns>Returns a ByteReader object</returns>
+    BYTE_ARRAY_OUT GetGeometry(INT32 index, INT32& length);
+
+    //////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the string value of the specified property. No conversion is
+    /// performed, thus the property must be a of type string or the result
+    /// is NULL</summary>
+    /// <param name="propertyName">Property name.</param>
+    /// <returns>Returns the string value.</returns>
+    const wchar_t* GetString(CREFSTRING propertyName, INT32& length);
+
+    //////////////////////////////////////////////////////////////////
+    ///<summary>
+    /// Serialize data to TCP/IP stream
+    ///</summary>
+    ///<param name="stream">
+    /// Stream
+    ///</param>
+    virtual void Serialize(MgStream* stream);
+
+    //////////////////////////////////////////////////////////////////
+    ///<summary>
+    /// Deserialize data from TCP/IP stream
+    ///</summary>
+    ///<param name="stream">
+    /// Stream
+    ///</param>
+    virtual void Deserialize(MgStream* stream);
+
+    virtual MgFeatureSet* GetFeatures(INT32 count);
+
+private:
+    Ptr<MgAgfReaderWriter> m_agfRw;
+    Ptr<MgFeatureReader> m_innerReader;
+    Ptr<MgCoordinateSystemTransform> m_transform;
+};
+
+#endif
\ No newline at end of file

Modified: sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.cpp
===================================================================
--- sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.cpp	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.cpp	2014-06-26 14:31:04 UTC (rev 8265)
@@ -1246,7 +1246,135 @@
     }
 }
 
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case exercises selecting features transformed to a specific coordinate system.
+///----------------------------------------------------------------------------
+void TestFeatureService::TestCase_SelectFeaturesWithXform()
+{
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if(serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestFeatureService.TestCase_SelectFeatures", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
 
+        Ptr<MgFeatureService> pService = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+        if (pService == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestCase_SelectFeatures", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        //Create our test data store
+        Ptr<MgFeatureSchema> fs = new MgFeatureSchema(L"Default", L"");
+        Ptr<MgClassDefinition> cls = new MgClassDefinition();
+        cls->SetName(L"Test");
+        
+        Ptr<MgDataPropertyDefinition> id = new MgDataPropertyDefinition(L"ID");
+        id->SetAutoGeneration(true);
+        id->SetDataType(MgPropertyType::Int32);
+        
+        Ptr<MgGeometricPropertyDefinition> geom = new MgGeometricPropertyDefinition(L"Geometry");
+        geom->SetGeometryTypes(MgFeatureGeometricType::Point);
+        geom->SetSpatialContextAssociation(L"Default");
+
+        Ptr<MgPropertyDefinitionCollection> props = cls->GetProperties();
+        Ptr<MgPropertyDefinitionCollection> idProps = cls->GetIdentityProperties();
+
+        props->Add(id);
+        props->Add(geom);
+        idProps->Add(id);
+
+        cls->SetDefaultGeometryPropertyName(L"Geometry");
+        Ptr<MgClassDefinitionCollection> classes = fs->GetClasses();
+        classes->Add(cls);
+
+        //We'll use a transform guaranteed to work. ArbitraryXY (unitA to unitB)
+        //We just check that the transformed values are not the original, that way
+        //we know that CS-Map did its job
+        Ptr<MgCoordinateSystemFactory> csFact = new MgCoordinateSystemFactory();
+        STRING srcWkt = csFact->ConvertCoordinateSystemCodeToWkt(L"XY-M");
+        STRING dstWkt = csFact->ConvertCoordinateSystemCodeToWkt(L"XY-IN");
+
+        Ptr<MgGeometryFactory> geomFact = new MgGeometryFactory();
+        Ptr<MgAgfReaderWriter> agfRw = new MgAgfReaderWriter();
+        Ptr<MgFileFeatureSourceParams> create = new MgFileFeatureSourceParams(L"OSGeo.SDF", L"Default", srcWkt, fs);
+        Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(L"Library://UnitTests/Data/TransformTest.FeatureSource");
+        pService->CreateFeatureSource(fsId, create);
+
+        //Populate data store with test points
+
+        Ptr<MgCoordinate> coord1 = geomFact->CreateCoordinateXY(-37.1020, 144.0020);
+        Ptr<MgPoint> pt1 = geomFact->CreatePoint(coord1);
+        Ptr<MgByteReader> agf1 = agfRw->Write(pt1);
+
+        Ptr<MgPropertyCollection> propVals = new MgPropertyCollection();
+        Ptr<MgGeometryProperty> pGeom = new MgGeometryProperty(L"Geometry", agf1);
+        propVals->Add(pGeom);
+
+        Ptr<MgFeatureReader> fr = pService->InsertFeatures(fsId, L"Default:Test", propVals);
+        fr->Close();
+
+        Ptr<MgCoordinate> coord2 = geomFact->CreateCoordinateXY(-37.2020, 144.2020);
+        Ptr<MgPoint> pt2 = geomFact->CreatePoint(coord2);
+        Ptr<MgByteReader> agf2 = agfRw->Write(pt2);
+
+        pGeom->SetValue(agf2);
+        fr = pService->InsertFeatures(fsId, L"Default:Test", propVals);
+        fr->Close();
+
+        //Now select from this data store
+        Ptr<MgFeatureQueryOptions> query = new MgFeatureQueryOptions();
+        Ptr<MgReader> reader = pService->SelectFeatures(fsId, L"Default:Test", query, dstWkt);
+        
+        CPPUNIT_ASSERT(reader->ReadNext());
+        CPPUNIT_ASSERT(!reader->IsNull(L"Geometry"));
+
+        Ptr<MgByteReader> txAgf1 = reader->GetGeometry(L"Geometry");
+        Ptr<MgGeometry> txGeom1 = agfRw->Read(txAgf1);
+        MgPoint* txPt1 = dynamic_cast<MgPoint*>(txGeom1.p);
+        CPPUNIT_ASSERT(txPt1 != NULL);
+        Ptr<MgCoordinate> txCoord1 = txPt1->GetCoordinate();
+
+        //TODO: Maybe we should really check that it matches the expected transformed result
+        CPPUNIT_ASSERT(txCoord1->GetX() != -37.1020);
+        CPPUNIT_ASSERT(txCoord1->GetY() != 144.0020);
+
+        CPPUNIT_ASSERT(reader->ReadNext());
+        CPPUNIT_ASSERT(!reader->IsNull(L"Geometry"));
+
+        Ptr<MgByteReader> txAgf2 = reader->GetGeometry(L"Geometry");
+        Ptr<MgGeometry> txGeom2 = agfRw->Read(txAgf2);
+        MgPoint* txPt2 = dynamic_cast<MgPoint*>(txGeom2.p);
+        CPPUNIT_ASSERT(txPt2 != NULL);
+        Ptr<MgCoordinate> txCoord2 = txPt2->GetCoordinate();
+
+        //TODO: Maybe we should really check that it matches the expected transformed result
+        CPPUNIT_ASSERT(txCoord2->GetX() != -37.2020);
+        CPPUNIT_ASSERT(txCoord2->GetY() != 144.2020);
+
+        reader->Close();
+    }
+    catch(MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(FdoException* e)
+    {
+        FDO_SAFE_RELEASE(e);
+        CPPUNIT_FAIL("FdoException occurred");
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+
 ///----------------------------------------------------------------------------
 /// Test Case Description:
 ///

Modified: sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.h
===================================================================
--- sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.h	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/Server/src/UnitTesting/TestFeatureService.h	2014-06-26 14:31:04 UTC (rev 8265)
@@ -38,6 +38,7 @@
     CPPUNIT_TEST(TestCase_DescribeSchema);
     CPPUNIT_TEST(TestCase_ApplySchema);
     CPPUNIT_TEST(TestCase_SelectFeatures);
+    CPPUNIT_TEST(TestCase_SelectFeaturesWithXform);
     CPPUNIT_TEST(TestCase_SelectAggregate);
     CPPUNIT_TEST(TestCase_UpdateFeaturesInsert);
     CPPUNIT_TEST(TestCase_UpdateFeaturesPartialFailure);
@@ -91,6 +92,7 @@
     void TestCase_DescribeSchema();
     void TestCase_ApplySchema();
     void TestCase_SelectFeatures();
+    void TestCase_SelectFeaturesWithXform();
     void TestCase_SelectAggregate();
     void TestCase_UpdateFeaturesInsert();
     void TestCase_UpdateFeaturesPartialFailure();

Modified: sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs
===================================================================
--- sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs	2014-06-26 11:37:30 UTC (rev 8264)
+++ sandbox/jng/convenience_apis/UnitTest/WebTier/DotNet/TestCommon/ExternalTests/ConvenienceTests.cs	2014-06-26 14:31:04 UTC (rev 8265)
@@ -467,4 +467,102 @@
         }
     }
 
+    public class SelectFeaturesWithTransform : IExternalTest
+    {
+        public void Execute(IPlatformFactory factory, ITestLogger logger)
+        {
+            MgFeatureService featSvc = (MgFeatureService)factory.CreateService(MgServiceType.FeatureService);
+
+            //Create our test data store
+            MgFeatureSchema fs = new MgFeatureSchema("Default", "");
+            MgClassDefinition cls = new MgClassDefinition();
+            cls.SetName("Test");
+        
+            MgDataPropertyDefinition id = new MgDataPropertyDefinition("ID");
+            id.SetAutoGeneration(true);
+            id.SetDataType(MgPropertyType.Int32);
+        
+            MgGeometricPropertyDefinition geom = new MgGeometricPropertyDefinition("Geometry");
+            geom.SetGeometryTypes(MgFeatureGeometricType.Point);
+            geom.SetSpatialContextAssociation("Default");
+
+            MgPropertyDefinitionCollection props = cls.GetProperties();
+            MgPropertyDefinitionCollection idProps = cls.GetIdentityProperties();
+
+            props.Add(id);
+            props.Add(geom);
+            idProps.Add(id);
+
+            cls.SetDefaultGeometryPropertyName("Geometry");
+            MgClassDefinitionCollection classes = fs.GetClasses();
+            classes.Add(cls);
+
+            //We'll use a transform guaranteed to work. ArbitraryXY (unitA to unitB)
+            //We just check that the transformed values are not the original, that way
+            //we know that CS-Map did its job
+            MgCoordinateSystemFactory csFact = new MgCoordinateSystemFactory();
+            string srcWkt = csFact.ConvertCoordinateSystemCodeToWkt("XY-M");
+            string dstWkt = csFact.ConvertCoordinateSystemCodeToWkt("XY-IN");
+
+            MgGeometryFactory geomFact = new MgGeometryFactory();
+            MgAgfReaderWriter agfRw = new MgAgfReaderWriter();
+            MgFileFeatureSourceParams create = new MgFileFeatureSourceParams("OSGeo.SDF", "Default", srcWkt, fs);
+            MgResourceIdentifier fsId = new MgResourceIdentifier("Library://UnitTests/Data/TransformTest.FeatureSource");
+            featSvc.CreateFeatureSource(fsId, create);
+
+            //Populate data store with test points
+
+            MgCoordinate coord1 = geomFact.CreateCoordinateXY(-37.1020, 144.0020);
+            MgPoint pt1 = geomFact.CreatePoint(coord1);
+            MgByteReader agf1 = agfRw.Write(pt1);
+
+            MgPropertyCollection propVals = new MgPropertyCollection();
+            MgGeometryProperty pGeom = new MgGeometryProperty("Geometry", agf1);
+            propVals.Add(pGeom);
+
+            MgFeatureReader fr = featSvc.InsertFeatures(fsId, "Default:Test", propVals);
+            fr.Close();
+
+            MgCoordinate coord2 = geomFact.CreateCoordinateXY(-37.2020, 144.2020);
+            MgPoint pt2 = geomFact.CreatePoint(coord2);
+            MgByteReader agf2 = agfRw.Write(pt2);
+
+            pGeom.SetValue(agf2);
+            fr = featSvc.InsertFeatures(fsId, "Default:Test", propVals);
+            fr.Close();
+
+            //Now select from this data store
+            MgFeatureQueryOptions query = new MgFeatureQueryOptions();
+            MgReader reader = featSvc.SelectFeatures(fsId, "Default:Test", query, dstWkt);
+        
+            Assert.IsTrue(reader.ReadNext());
+            Assert.IsTrue(!reader.IsNull("Geometry"));
+
+            MgByteReader txAgf1 = reader.GetGeometry("Geometry");
+            MgGeometry txGeom1 = agfRw.Read(txAgf1);
+            MgPoint txPt1 = (MgPoint)txGeom1;
+            Assert.IsTrue(txPt1 != null);
+            MgCoordinate txCoord1 = txPt1.GetCoordinate();
+
+            //TODO: Maybe we should really check that it matches the expected transformed result
+            Assert.IsTrue(txCoord1.GetX() != -37.1020);
+            Assert.IsTrue(txCoord1.GetY() != 144.0020);
+
+            Assert.IsTrue(reader.ReadNext());
+            Assert.IsTrue(!reader.IsNull("Geometry"));
+
+            MgByteReader txAgf2 = reader.GetGeometry("Geometry");
+            MgGeometry txGeom2 = agfRw.Read(txAgf2);
+            MgPoint txPt2 = (MgPoint)txGeom2;
+            Assert.IsTrue(txPt2 != null);
+            MgCoordinate txCoord2 = txPt2.GetCoordinate();
+
+            //TODO: Maybe we should really check that it matches the expected transformed result
+            Assert.IsTrue(txCoord2.GetX() != -37.2020);
+            Assert.IsTrue(txCoord2.GetY() != 144.2020);
+
+            reader.Close();
+        }
+    }
+
 }



More information about the mapguide-commits mailing list